//	┌───────────────────────────────────────────┐
//	│   KOC POWER ALL - ELITE		    │
//	│   PLUGIN: Buttler			    │
//	│   VERSION: 1.0	 		    │
//	└───────────────────────────────────────────┘	


ksxVersion = "2014.06.01";
ksxEnabled = true;
ksxDebug = false;
/* [2012-06-03]
 * ADD Button Item Salvage
 */
/* [2012-05-07]
 * FIX Repeat Button Catapult not filled out
 */
/* [2012-05-05]
 * DEL Crest Restart Workaround disabled
 */
/* [2012-05-02]
 * FIX MarchExtenderPlugin: method to fill out values
 */
/* [2012-04-17]
 * UPD Crest Button uses code direct
 * FIX Crest Restart Workaround
 */
/* [2012-04-16]
 * FIX Repeat Scout (only Workaround)
 */
/* [2012-03-14]
 * NEW Button for SupplyState
 * UPD new button sync logic, can now use code
 * UPD ksxpbTraderState, ksxpdxSupplyState use new sync logic 
 */
/* [2012-03-12]
 * UPD ResourceRequestPlugin Aethterstones
 * UPD MarchExtenderPlugin Aethterstones
 */


//#region Main

//DEBUGCODE for finding the proper page
//if(ksxDebug) GM_log("Loading document: " +
//	"id=" + document.getElementsByTagName("html")[0].getAttribute("id") + " title: " + document.title + 
//	" \n\t" + "href: " + document.location.href);

// @include       *.kingdomsofcamelot.com/fb/e2/src/main_src.php*
if (ksxEnabled && document.body.id == 'mainbody') {
	//	/*DEBUGCODE:*/if(ksxDebug) GM_log("Setup KoC Buttler \n" + "location: " + document.location.href);

	ksx = uW.ksx = new KsxLibrary();
	//ksx.koc.lang = ksx.koc.getLanguage();
	ksx.koc.lang = LangOptions.culang;
	ksx.compatibility.disableMarchXYPaste = false; // [Attack]

	//GM_log("INFO: language " + ksx.koc.lang + " / " + culang.ksx_KoCButtler_language);
	//special configuration removed into plugin
	
	// Toolbar Configuration
	ksx.configuration.toolbar = {items: []};
	ksx.configuration.toolbar.items.push(["Button", , culang.ksx_KoCButtler_Toolbar_NewMessage, "ksx.plugins.Toolbar.macros.newMessage(); return false;"]);
	ksx.configuration.toolbar.items.push(["Button", , culang.ksx_KoCButtler_Toolbar_MyReports, "modal_messages();track_chrome_btn('messages_btn');Messages.listReports();return false;"]);
	//ksx.configuration.toolbar.items.push(["Button", , "R", "ksx.tools.click('//*[@id=\"pbtcBerichte\"]/a'); return false;"]);
	ksx.configuration.toolbar.items.push(["Button", , culang.ksx_KoCButtler_Toolbar_AllianceReports, "modal_alliance();track_chrome_btn('alliance_btn');allianceReports();modal_alliance_changetab(4);return false;"]);
	//			["Button", , "Einladung", "modal_alliance();track_chrome_btn('alliance_btn');inviteFriendsModule();return false;"],
	//NOTWORKING["Button", , "Einladung", "modal_alliance();track_chrome_btn('alliance_btn');inviteFriendsModule();WAIT;searchTabInAllianceInvite();return false;"],
	//			["LineBreak"],	
	ksx.configuration.toolbar.items.push(["Separator", ]);
	//			["Button",, "Truppen aussenden", "modal_attack(4,'','');return false;"],
	//			["Button", , "Sp?h", "ksx.plugins.Toolbar.macros.newMarch(3, '','', [0,0,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0] );return false;"],
	ksx.configuration.toolbar.items.push(["Button", , culang.mainReinforce, "ksx.plugins.Toolbar.macros.newMarch(2, '','', [0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0] );return false;"]);
	ksx.configuration.toolbar.items.push(["Button", , culang.mainReassign, "ksx.plugins.Toolbar.macros.newMarch(5, '','', [0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0] );return false;"]);
	ksx.configuration.toolbar.items.push(["Button", , culang.mainTransport, "ksx.plugins.Toolbar.macros.newMarch(1, '','', [0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0] );return false;"]);
	ksx.configuration.toolbar.items.push(["Button", "ksxMarchExtenderRepeatOpen", "Repeat", ""]);
	//			["Button","ksxMarchExtenderRepeatMarch", "Wiederholen!"     , ""],
	//ksx.configuration.toolbar.items.push(["Button",, "Dump Seed"        , "ksx.plugins.Toolbar.macros.dumpSeed(); return false;"]);
	//ksx.configuration.toolbar.items.push(["Button",, "Dump Throne"        , "ksx.plugins.Toolbar.macros.dumpThroneItems(); return false;"]);
	
	ksx.configuration.powertoolbar = {items: [], syncButtons: []};
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbTraderState", culang.mainTransport+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpdxSupplyState", culang.shrsupply+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbReassignState", culang.tabLabelReassign+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["Separator"]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbCrest", culang.tabLabelCrest+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbDarkForest", culang.mainDarkForest+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["Separator"]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbRaidStart", culang.raidAutoReset+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbEveryEnable", culang.ksx_KoCButtler_PowerToolbar_autoRefresh+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["LineBreak"]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbBuildRunning", culang.buildButton+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbBuildMode", culang.buildMode+" ${[x]}", ""]);
//	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbHelpRequest", culang.buildAskForHelp+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["Separator"]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbAutoTrain", culang.buttonAutoTrain+" ${[x]}", ""]);	
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbCrafting", culang.craftButton+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbsalvage_run", culang.throneStuffAutoSalvage+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["Separator"]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbAttackSet", "T-Set " + culang.mainAttack + " ${[x]}", ""]); //16.10.2012 Bommel
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbRestoreSet", "T-Set " + culang.mainEnd + " ${[x]}", ""]); //16.10.2012 Bommel
	ksx.configuration.powertoolbar.items.push(["LineBreak"]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbDFOld", culang.OldmainDarkForestLabel+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbWildAttack", culang.mainWildAttack+" ${[x]}", ""]);
	ksx.configuration.powertoolbar.items.push(["Button", "ksxpbAttack", culang.mainAttack+" ${[x]}", ""]);
	// A): ["{ToolbarButtonID}" , "{PowerButtonID}" , "value"            , "{TrueCondition}" ] :: for a button
	// A): ["{ToolbarButtonID}" , "{PowerButtonID}" , "checked"          , "true"            ] :: for a checkbox
	// B): ["{ToolbarButtonID}" , "P:{StatePath}"   , "M:{ToggleMethod}" , ""                ] :: code direct
 ksx.configuration.powertoolbar.syncButtons = [
		// ["ksxpbTraderState"  , "pbTraderState", "value", " = " +culang.buttonon], //obsolete method to sync
		["ksxpbTraderState"  , "P:Tabs.Transport.traderState.running", "M:Tabs.Transport.toggleTraderState()", ""],
		["ksxpdxSupplyState"  , "P:Tabs.Transport.reapproState.running", "M:Tabs.Transport.toggleReapproState()", ""],
		["ksxpbReassignState", "P:Tabs.Reassign.reassignState.running", "M:Tabs.Reassign.toggleReassignState()", ""],
		["ksxpbBuildRunning", "pbBuildRunning", "value", " = "+culang.buttonON],
		["ksxpbBuildMode", "pbBuildMode", "value", " = "+culang.buttonON],
		["ksxpbRaidStart", "pbRaidStart", "value", " = "+culang.buttonON],
		["ksxpbAutoTrain", "P:TrainOptions.Running", "M:Tabs.AutoTrain.toggleAutoTrainState()", ""],
		["ksxpbCrafting", "P:Tabs.AutoCraft.options.running", "M:Tabs.AutoCraft.toggleCraftStateRunning()", ""],
//		["ksxpbCrest", "Cresttoggle", "value", " = "+culang.buttonON],
		["ksxpbCrest", "P:Options.crestRunning", "M:Tabs.Crest.toggleCrestState()", ""],
		["ksxpbDarkForest", "AttSearch", "value", " = "+culang.buttonON],
		["ksxpbHelpRequest"  , "pbHelpRequest", "checked","true"],
		["ksxpbEveryEnable", "pbEveryEnable", "checked", "true"],
 //!?!	["ksxpbEveryEnable", "P:Options.pbEveryEnable", "M:if(Options.pbEveryEnable ){Options.pbEveryEnable=false;}else {Options.pbEveryEnable=true;} RefreshEvery.setEnable(Options.pbEveryEnable) ", ""],
		["ksxpbsalvage_run"  , "P:Options.ThroneDeleteItems", "M:Tabs.ThroneStuff.toggleSalvage()", ""],
		["ksxpbAttackSet"  , "P:Options.alertConfig.changeThrone", "M:changeThrone()", ""],
		["ksxpbRestoreSet"  , "P:Options.alertConfig.returnThrone", "M:returnThrone()", ""],
		["ksxpbDFOld", "P:Options.AttackRunning", "M:Tabs.DarkForest.toggleBarbState()", ""],
		["ksxpbWildAttack", "P:WildOptions.Running", "M:Tabs.WildAttack.toggleWildState()", ""],
		["ksxpbAttack", "P:AtkOptions.Running", "M:Tabs.Attack.toggleAttackState()", ""],
	]
	
	// Chat Configuration
	ksx.configuration.chat = {
		enableTimeCorrection: true,
		backgrounds: {
			RequestItemBackground: 'lightgreen',
			OwnItemBackground    : 'lightgray',
			InfoBackground       : "#E0E060",   //Colors.SpamBackground,
			//AllyAttackBackground : "#FFB0E0",
			//OwnAttackBackground  : "#FF8080"
		}
	};
	
	//if (Options.DeskInfo       ) ksx.plugins.DeskInfo        = new DeskInfoPlugin(ksx);              
	ksx.plugins.Toolbar         = new ToolbarPlugin(ksx);
	ksx.plugins.PowerToolbar    = new PowerToolbarPlugin(ksx);
	ksx.plugins.ChatMonitor     = new ChatMonitorPlugin(ksx);
	ksx.plugins.ResourceRequest = new ResourceRequestPlugin(ksx); //requires ChatMonitor
	ksx.plugins.MarchExtender   = new MarchExtenderPlugin(ksx);   //requires Toolbar
	ksx.plugins.Reports         = new ReportsPlugin(ksx);         //requires Toolbar	

	// ### Crest Restart Workaround ###
	// ERR: sometimes new crest marches are not startet, may be because timeout (march returns) or whatever
	// FIX: if crest is ON it will toggle OFF/ON all 5 minutes, this will restart the crest function
	if(false) setInterval(function(){ 
		//GM_log("Crest Restart Workaround")
		if(!Options.crestRunning) return;
		//GM_log("Crest Restart Workaround Toggle OFF")
		Tabs.Crest.toggleCrestState();
		setTimeout(function(){ 
			if(Options.crestRunning) return;
			//GM_log("Crest Restart Workaround Toggle ON")
			Tabs.Crest.toggleCrestState();
		},500);
	}, 5*60*1000);
	
	// ### XY paste on map
	if (!ksx.compatibility.disableMarchXYPaste)
		ksx.koc.attachXYPaste('mapXCoor', 'mapYCoor');
}
//#endregion
function changeThrone() {
	if (Options.alertConfig.changeThrone) {
		Options.alertConfig.changeThrone = false;
		ById('Ksalertthrone').checked = false;
		Options.alertConfig.returnThrone = false;
		ById('KsalertthroneRet').checked = false;
		Options.alertConfig.RecentActivity = false;
	} else {
		Options.alertConfig.changeThrone = true;
		ById('Ksalertthrone').checked = true;
	}
	saveOptions();
}
function returnThrone() {
	if (Options.alertConfig.returnThrone) {
		Options.alertConfig.returnThrone = false;
		ById('KsalertthroneRet').checked = false;
		Options.alertConfig.RecentActivity = false;
	} else {
		Options.alertConfig.returnThrone = true;
		ById('KsalertthroneRet').checked = true;
	}
	saveOptions();
}



function KsxLibrary() {
	if(ksxDebug) GM_log(new Date().toTimeString().substring(0, 8) + '.' + new Date().getMilliseconds() + ': ' + "KsxLibrary");
	
	//var JSON= {}; (function () { "use strict"; function f(n) { return n < 10 ? '0' + n : n; } if (typeof Date.prototype.toJSON !== 'function') { Date.prototype.toJSON = function (key) { return isFinite(this.valueOf()) ? this.getUTCFullYear() + '-' + f(this.getUTCMonth() + 1) + '-' + f(this.getUTCDate()) + 'T' + f(this.getUTCHours()) + ':' + f(this.getUTCMinutes()) + ':' + f(this.getUTCSeconds()) + 'Z' : null; }; String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function (key) { return this.valueOf(); }; } var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"': '\\"', '\\': '\\\\' }, rep; function quote(string) { escapable.lastIndex = 0; return escapable.test(string) ? '"' + string.replace(escapable, function (a) { var c = meta[a]; return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }) + '"' : '"' + string + '"'; } function str(key, holder) { var i, k, v, length, mind = gap, partial, value = holder[key]; if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); } if (typeof rep === 'function') { value = rep.call(holder, key, value); } switch (typeof value) { case 'string': return quote(value); case 'number': return isFinite(value) ? String(value) : 'null'; case 'boolean': case 'null': return String(value); case 'object': if (!value) { return 'null'; } gap += indent; partial = []; if (Object.prototype.toString.apply(value) === '[object Array]') { length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || 'null'; } v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']'; gap = mind; return v; } if (rep && typeof rep === 'object') { length = rep.length; for (i = 0; i < length; i += 1) { k = rep[i]; if (typeof k === 'string') { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } else { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}'; gap = mind; return v; } } if (typeof JSON.stringify !== 'function') { JSON.stringify = function (value, replacer, space) { var i; gap = ''; indent = ''; if (typeof space === 'number') { for (i = 0; i < space; i += 1) { indent += ' '; } } else if (typeof space === 'string') { indent = space; } rep = replacer; if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) { throw new Error('JSON.stringify'); } return str('', { '': value }); }; } if (typeof JSON.parse !== 'function') { JSON.parse = function (text, reviver) { var j; function walk(holder, key) { var k, v, value = holder[key]; if (value && typeof value === 'object') { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); } text = String(text); cx.lastIndex = 0; if (cx.test(text)) { text = text.replace(cx, function (a) { return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); }); } if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { j = eval('(' + text + ')'); return typeof reviver === 'function' ? walk({ '': j }, '') : j; } throw new SyntaxError('JSON.parse'); }; } } ());
	this.JSON = JSON;

	String.prototype.trim = function() { return this.replace( /^\s+|\s+$/g , ''); };
	
	this.logit = function(msg) {
		var now = new Date();
		GM_log(this.koc.getServerId() + ' @ ' + now.toTimeString().substring(0, 8) + '.' + now.getMilliseconds() + ': ' + msg);
	};

	var tools = {

		getElement: function (locator, logError) {
			//TODO: implement functionality of Selenium element locators
			// http://release.seleniumhq.org/selenium-core/1.0/reference.html
			if (locator.search('//') == 0) return this.getElementByXPath(locator, logError);
			if (locator.search('xpath=') == 0) return this.getElementByXPath(locator.substr(6, locator.length - 6), logError);
			//TODO: if (locator.search('css=') == 0) return this.getElementByCssPath(locator.substr(4, locator.length - 4), logError);
			//TODO: if (locator.search('document.') == 0) return this.getElementByDom(locator.substr(4, locator.length - 4), logError);
			//TODO: if (locator.search('dom=') == 0) return this.getElementByDom(locator.substr(4, locator.length - 4), logError);
			if (locator.search('id=') == 0) return this.getElementById(locator, logError);
			//TODO: if (locator.search('link=') == 0) return document.getElementByLink(locator);
			//TODO: if (locator.search('identifier=') == 0) ...
			var elmt = ById(locator); if (elmt != null) return elmt;
			elmt=document.getElementsByName(locator);
			if (logError && !elmt) GM_log("WARNING: locator not found!" + "\n\tlocator: " + locator + "\n\tUniqueID: {04003277-0D38-4D60-996B-7F0EA5AA04E9}" + (typeof logError !== "boolean" ? "\n\tTag: " + logError : ""));
			return elmt;
		},

		//used by getElement
		/*private*/ getElementById: function (locator, logError) {
			var elmt = ById(locator);
			if (logError && !elmt) GM_log("WARNING: locator not found!" + "\n\tlocator: " + locator + "\n\tUniqueID: {4DFB36F4-F2D6-4982-87E6-8A2A8957E74E}" + (typeof logError !== "boolean" ? "\n\tTag: " + logError : ""));
			return elmt;
		},

		//used by getElement
		/*private*/ getElementByXPath: function (expr, logError) {
			var d = document;
			var elmFirstResult = d.evaluate(expr, document,
				null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
			if (logError && !elmFirstResult) GM_log("WARNING: locator not found!" +"\n\tlocator: " + expr + "\n\tUniqueID: {29D43133-ADCE-473F-A9E1-C61CD1EA005E}" +(typeof logError !== "boolean" ? "\n\tTag: " + logError : ""));
			return elmFirstResult;
		},

		//TODO: getElementByCssPath: function (expr) {},
		//TODO: getElementByDom: function (expr) {},
		//TODO: getElementByLink: function (expr) {},

		getAttribute: function (attributeLocator) {
			var index = attributeLocator.lastIndexOf('@');
			var locator = attributeLocator.substr(0, index);
			var attribute = attributeLocator.substring(index + 1, attributeLocator.length);
			//alert(locator + " " + attribute);
			var elmt = this.getElement(locator);
			var attrValue = elmt.getAttribute(attribute);
			return attrValue;
		},

		click: function (element) {
			if (element === null || element === undefined) throw "Element not specified!";
			if (typeof (element) == "string") element = this.getElement(element);

			var evt = document.createEvent("MouseEvents");
			evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
			var canceled = !element.dispatchEvent(evt);
			//OPTIONAL: if (canceled) { /* A handler called preventDefault */ } else {/* None of the handlers called preventDefault*/}
		},

		uncheck: function (element) {
			if (element === null || element === undefined) throw "Element not specified!";
			if (typeof (element) == "string") element = this.getElement(element);
			if (typeof element.checked == "undefined") return; //Klick-Buttons (input type="button")  Checkboxen(input type="checkbox")  Radio-Buttons(input type="radio") 
			if (!element.checked) return;

			var evt = document.createEvent("MouseEvents");
			evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
			var canceled = !element.dispatchEvent(evt);
			//OPTIONAL: if (canceled) { /* A handler called preventDefault */ } else {/* None of the handlers called preventDefault*/}
		},

		check: function (element) {
			if (element === null || element === undefined) throw "Element not specified!";
			if (typeof (element) == "string") element = this.getElement(element);
			if (typeof element.checked == "undefined") return;

			if (element.checked) return;

			var evt = document.createEvent("MouseEvents");
			evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
			var canceled = !element.dispatchEvent(evt);
			//OPTIONAL: if (canceled) { /* A handler called preventDefault */ } else {/* None of the handlers called preventDefault*/}
		},

		typeKeys: function (element, chars) {
			if (element == null) throw "Element not specified!";
			if (typeof (element) == "string") element = this.getElement(element);
			for (var i = 0; i < chars.length; i++) {
				// Create the key press event.
				var pressEvent = document.createEvent('KeyboardEvent');
				pressEvent.initKeyEvent("keypress", true, true, window, false, false, false, false, 0, chars.charCodeAt(i));

				element.dispatchEvent(pressEvent); // Press the key.
			}
		},

		typeKeys2: function (element, chars) {
			if (element == null) throw "ERROR: typeKeys2 - Element not specified!";
			if (typeof (element) == "string") element = this.getElement(element);

			element.focus();

			for (var i = 0; i < String(chars).length; i++) {
				var c = String(chars).charCodeAt(i);

				var downEvent = document.createEvent('KeyboardEvent');
				downEvent.initKeyEvent("keydown", true, true, window, false, false, false, false, 0, c);
				element.dispatchEvent(downEvent);

				var pressEvent = document.createEvent('KeyboardEvent');
				pressEvent.initKeyEvent("keypress", true, true, window, false, false, false, false, 0, c);
				element.dispatchEvent(pressEvent);

				var upEvent = document.createEvent('KeyboardEvent');
				upEvent.initKeyEvent("keyup", true, true, window, false, false, false, false, 0, c);
				element.dispatchEvent(upEvent);
			}
		},

		type: function (element, chars) {
			if (element == null) throw "Element not specified!";
			if (typeof (element) == "string") element = this.getElement(element);

			if (element.type == 'text') {
				element.focus();
				element.value = chars;
			} else {
				throw "Element not supported!";
			}
		},

		emulateFocus: function (element) {
			emulateEvent(element, "focus");
		},

		emulateEvent: function (element, eventName) {
			var options = extend(defaultOptions, arguments[2] || {});
			var oEvent, eventType = null;
			for (var name in eventMatchers) {
				if (eventMatchers[name].test(eventName)) { eventType = name; break; }
			}
			if (!eventType) throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported');
			if (document.createEvent) {
				oEvent = document.createEvent(eventType);
				if (eventType == 'HTMLEvents') {
					oEvent.initEvent(eventName, options.bubbles, options.cancelable);
				} else {
					oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView,
					 	options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
					 	options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element);
				}
				element.dispatchEvent(oEvent);
			} else {
				options.clientX = options.pointerX;
				options.clientY = options.pointerY;
				var evt = document.createEventObject();
				oEvent = extend(evt, options);
				element.fireEvent('on' + eventName, oEvent);
			}
			return element;
		},

		extend: function (destination, source) {
			for (var property in source) destination[property] = source[property];
			return destination;
		},

		eventMatchers: {
			'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,
			'MouseEvents': /^(?:click|dblclick|mouse(?:down|up|over|move|out))$/
		},
		defaultOptions: { pointerX: 0, pointerY: 0, button: 0, ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, bubbles: true, cancelable: true },

		douW: function (func, executeByEmbed) {
			if (this.isChrome || executeByEmbed) {
				var scr = document.createElement('script');
				scr.innerHTML = func;
				document.body.appendChild(scr);
			} else {
				try {
					eval("uW." + func);
				} catch (error) {
					logit("Bei DouW hat JavaScript ein fehler gefunden! Meldung: " + error.description);
				}
			}
		},

		findParentByTagName: function (elmt, tagName, findSelf) {
			if (findSelf && elmt.tagName.toLowerCase() == tagName.toLowerCase()) return elmt;
			var t = elmt;
			while (t) {
				try { t = t.parentNode; } catch (ex) { return null; };
				if (t == null) return null;
				//GM_log(t.tagName);
				if (t.tagName.toLowerCase() == tagName.toLowerCase()) break;
			}
			return t;
		},
		
		typeOf:function(v) {
			if (v == undefined) return 'undefined';
			if (typeof(v) == 'object') {
				if (!v) return 'null';
		//    else if (uW.Object.prototype.toString.apply(v) === '[object Array]')
				else if (v.constructor.toString().indexOf("Array") >= 0 && typeof(v.splice) == 'function') return 'array';
				else return 'object';
			}
			return typeof(v);
		},

		className: "KSX+Tools"
	};
	this.tools = tools;

	var selenium = {
		// a small try to implement some Selenium functionality

		click: function(locator) {
			logit("Selenium: click | " + locator);
			var elmt = tools.getElement(locator);
			if (elmt == null) {
				throw "Element not found (" + locator + ")";
			}
			tools.click(elmt);
		},

		getAttribute: function(attributeLocator) {
			logit("Selenium: getAttribute | " + attributeLocator);
			return tools.getAttribute(attributeLocator);
		},

		getElement: function(locator) {
			logit("Selenium: getElement | " + locator);
			return tools.getElement(locator);
		},

		getElementPresent: function(locator) {
			logit("Selenium: getElementPresent | " + locator);
			return tools.getElement(locator) != null;
		},

		waitforElementPresent: function(locator) {
			logit("Selenium: waitforElementPresent | " + locator);
			var tot = new Date().getTime() + 30000;

			do { //because there is no sleep, this will use 100% CPU :-( 
				if (tools.getElementPresent(locator)) return true;
			} while (new Date().getTime() < tot)
			throw "Timeout on waiting for element!";
		},

		className: "KSX.Selenium"
	};
	this.Selenium = selenium;

	/// <summary> Provides funtions to create HTML elements </summary>
	var builder = {

		/// <summary>Creates a blue button </summary>
		BlueButton: function (caption, onclick, id) {
			var a = document.createElement('a');
			if (typeof (onclick) == "string") { a.setAttribute("onclick", onclick); }
			else if (typeof (onclick) == "function") { a.addEventListener("click", onclick, true); }
			else throw "Invalid argument!";
			a.setAttribute("class", "button20");
			a.setAttribute("href", "#");
			if (id) a.setAttribute("id", id);
			var span = document.createElement('span');
			a.appendChild(span);
			span.appendChild(document.createTextNode(caption));
			return a;
		},

		//TODO: DRAFT same as BlueButton but inline
		BlueButton2: function (caption, onclick, id) {
			var a = document.createElement('a');
			if (typeof (onclick) == "string") { a.setAttribute("onclick", onclick); }
			else if (typeof (onclick) == "function") { a.addEventListener("click", onclick, true); }
			else throw "Invalid argument!";
			a.setAttribute("style", "background: url('img/button20_cap.png') no-repeat scroll right top transparent;color: #FFFFFF;cursor: pointer;display: inline; font-size: 12px; font-weight: bold; height: 22px; margin-left: 6px; margin-right: 6px; margin-right: 6px; margin-right: 6px; padding: 2px 8px 5px 0px; text-decoration: none;");
			if (id) a.setAttribute("id", id);
			var span = document.createElement('span');
			span.setAttribute("style", "background: url('img/button20.png') no-repeat scroll 0 0 transparent; padding: 2px 0 5px 8px;");
			a.appendChild(span);
			span.appendChild(document.createTextNode(caption));
			return a;
		},
		ToolbarButton: function (caption, onclick, id) {
			// TODO KSX replace koc-power-pdx.googlecode.com referrence. (Not allowed in library)
			var checked = IMGCheckboxChecked;
			var unchecked = IMGCheckboxUnchecked;
			var unknown = IMGCheckboxUnknown;
			
			var a = document.createElement('a');
			if (typeof (onclick) == "string") { a.setAttribute("onclick", onclick); }
			else if (typeof (onclick) == "function") { a.addEventListener("click", onclick, true); }
			else throw "Invalid argument!";
			a.setAttribute("style", "background: url('img/button20_cap.png') no-repeat scroll right top transparent;color: #DFDFFF;cursor: pointer;display: inline; font-size: 11px; font-weight: bold; height: 22px; margin-right:1px;margin-left:1px; padding: 2px 8px 5px 0px; text-decoration: none;");
			if (id) a.setAttribute("id", id);
			var span = document.createElement('span');
			span.setAttribute("style", "background: url('img/button20.png') no-repeat scroll 0 0 transparent; line-height: 15px; padding: 2px 0 5px 8px;");
			a.appendChild(span);
			//span.appendChild(document.createTextNode(caption));
			//caption = caption.replace("${[x]}", "<span style='color:#00FF00; font-size:16px; vertical-align:middle;'>"+culang.shrbtnchecked+"</span>"); //?
			caption = caption.replace("${[x]}", "<img alt='checked' src='"+checked+"'/>"); 
			//caption = caption.replace("${[ ]}", "<span style='color:#FF4444; font-size:16px; vertical-align:middle;'>"+culang.shrbtnnotchecked+"</span>");
			caption = caption.replace("${[ ]}", "<img alt='unchecked' src='"+unchecked+"'/>"); 
			//caption = caption.replace("${[?]}", "<span style='color:#AAAAAA; font-size:16px; vertical-align:middle;'>"+culang.shrbtnnotfound+"</span>");
			caption = caption.replace("${[ ]}", "<img alt='unknown' src='"+unknown+"'/>"); 
			
			span.innerHTML = caption;
			return a;
		},

		setToolbarCheckButton: function (button, value) {
			// TODO KSX replace koc-power-pdx.googlecode.com referrence. (Not allowed in library)
			var checked = IMGCheckboxChecked;
			var unchecked = IMGCheckboxUnchecked;
			var unknown = IMGCheckboxUnknown;
			
			var chk = button.childNodes[0].childNodes[button.childNodes[0].childNodes.length-1];
//			if (chk.innerHTML != ""+culang.shrbtnnotfound+"" && chk.innerHTML != ""+culang.shrbtnchecked+"" && chk.innerHTML != ""+culang.shrbtnnotchecked+"") {
//				GM_log("Invalid CheckButton content! '" + chk.innerHTML + "'");
//				return;
//			}
//			chk.style.color = value === null ? "#AAAAAA" : (value ? "#00FF00" : "#FF4444");
//			chk.innerHTML = value === null ? ""+culang.shrbtnnotfound+"" : (value ? ""+culang.shrbtnchecked+"" : ""+culang.shrbtnnotchecked+"");
			chk.alt = value === null ? "unknown" : (value ? "checked" : "unchecked");
			chk.src = value === null ? unknown : (value ? checked : unchecked);
		},

		ComTabButton: function (caption, onclick, id) {
			var comTabButtonStyle = 'margin-left: 10px; line-height: 35px;';
			var a = document.createElement('a');
			if (typeof (onclick) == "string") { a.setAttribute("onclick", onclick); }
			else if (typeof (onclick) == "function") { a.addEventListener("click", onclick, true); }
			else throw "Invalid argument!";
			a.setAttribute("style", "text-decoration: none; font-weight:bold; color:#FFF; font-variant:small-caps; ");
			if (id) a.setAttribute("id", id);
			var span = document.createElement('span');
			span.setAttribute("style", comTabButtonStyle);
			a.appendChild(span);
			span.appendChild(document.createTextNode(caption));
			return a;
		},

		/// <summary>Creates a blue tab </summary>
		BlueTab: function (caption, onclick, id) {
			var a = document.createElement('a');
			if (typeof (onclick) == "string") { a.setAttribute("onclick", onclick); }
			else if (typeof (onclick) == "function") { a.addEventListener("click", onclick, true); }
			else throw "Invalid argument!";
			a.setAttribute("class", "tab");
			if (id) a.setAttribute("id", id);
			var span = document.createElement('span');
			a.appendChild(span);
			span.appendChild(document.createTextNode(caption));
			return a;
		},

		/// <summary>Creates a green button </summary>
		GreenButton: function (caption, onclick, id) {
			var a = document.createElement('a');
			if (typeof (onclick) == "string") { a.setAttribute("onclick", onclick); }
			else if (typeof (onclick) == "function") { a.addEventListener("click", onclick, true); }
			else throw "Invalid argument!";
			a.setAttribute("class", "buttonGreen20");
			a.setAttribute("href", "#");
			if (id) a.setAttribute("id", id);
			var span = document.createElement('span');
			a.appendChild(span);
			span.appendChild(document.createTextNode(caption));
			return a;
		},

		Span: function (innerHtml, id) {
			var span = document.createElement('span');
			span.innerHTML = innerHtml;
			if (id) a.setAttribute("id", id);
			return span;
		},

		Element: function (elementName, innerElement) {
			var elmt = document.createElement(elementName);
			if (typeof (innerElement) == "object") elmt.appendChild(innerElement);
			else if (typeof (innerElement) == "string") elmt.innerHTML = innerElement;
			else throw "Invalid Argument!";
			return elmt;
		},

		remove: function (id) {
			var elmt = ById(id);
			if (!elmt) return;
			elmt.parentNode.removeChild(elmt);
		},

		//TODO KSX remove function or KoC dependency!
		showDialog: function (header, content) {
			var template = " \
	<div id='modalBox2' class='modalBox modalBox400 ' style='width: 416px; top: 150px; \
		left: 172px; z-index: 100310;'> \
		<div id='modalInner2' class='modalInner modalInner400'> \
			<div id='modalTitleBar2' class='modalTitleBar modalTitleBar400'> \
				<div id='modalTitle2' class='modalTitle'> \
					${Header} \
				</div> \
				<div id='modalControls2' class='modalControls'> \
					<a id='modalControlsClose2' onclick='ksx.Builder.remove(\"modalBox2\");return false;'><span>&nbsp;</span> </a> \
				</div> \
			</div> \
			<div id='modalContent2' class='modalContent modalContent400'> \
				<div class='kofcalert'> \
					${Content} \
				</div> \
				<div class='kofcalertbtn clearfix'> \
					<a class='button20' onclick='ksx.Builder.remove(\"modalBox2\");return false;'><span>Ok</span> </a> \
				</div> \
			</div> \
		</div> \
	</div>";

			var s = template.replace("${Header}", header).replace("${Content}", content);
			document.body.appendChild(ksx.Builder.Element("div", s));
		},

		className: "KSX.Builder"
	};
	this.Builder = builder;
	
	/// <summary> Provides KoC specific stuff </summary>
	this.koc = {
		_ServerID: null,
		getServerId: function () {
			if (this._ServerID == null) {
				var m = /^[a-zA-Z]+([0-9]+)\./.exec(document.location.hostname);
				if (m)
					this._ServerId = m[1];
				else
					this._ServerId = '??';
			}
			return this._ServerId;
		},

		_PlayerName: null,
		getPlayerName: function () {
			///*DEBUGCODE:*/alert("Calling ksx.koc.getPlayerName");
			if (this._PlayerName == null) {
				var e = tools.getElement("topnavDisplayName");
				///*DEBUGCODE:*/if (e == null) alert("topnavDisplayName not found!");
				this._PlayerName = e.textContent;
			};
			return this._PlayerName;
		},

		getRallyPointLevel: function (cityId, returnLogicalLevel) {
			if (!cityId) cityId = uW.currentcityid;
			else if (city.indexOf("city") != 0) cityId = "city" + cityId;
			if (!returnLogicalLevel) returnLogicalLevel = false;
			var seed = uW.seed;
			var rallypointLevel = 0;
			for (var o in seed.buildings[cityId]) {
				if (parseInt(seed.buildings[cityId][o][0]) == 12) {
					rallypointLevel = parseInt(seed.buildings[cityId][o][1]);
					break;
				}
			}
			if (returnLogicalLevel && rallypointLevel == 11) rallypointLevel = 15;
			return rallypointLevel;
		},

		getCurrentCityId: function () {
			return uW.currentcityid; //"city12345567"
		},

		getCurrentMarchType: function () {
			for (var i = 1; i < 6; i++) if (ById('modal_attack_tab_' + i).className == 'selected') return i;
			return 0;
		},

		// Provides a wrapper for the KoC march popup
		MarchUI: function () {
			try {
				for (var i = 1; i <= 12; i++) {
					// this.unitIpt? = ksx.tools.getElement("modal_attack_unit_ipt?");
					var elmt1 = ksx.tools.getElement("modal_attack_unit_ipt" + i, true);
					this["unitIpt" + i] = elmt1;

					// this.unitnum? = ksx.tools.getElement("//div[@id='modal_attack_unitlist']/div[@name='?']/div/div[2]/span");
					var elmt2 = ksx.tools.getElement("//div[@id='modal_attack_unitlist']/div[@name='" + i + "']/div/div[2]/span", true);
					this["unitnum" + i] = elmt2;
					
					this["unitAvail" + i] = Number(elmt2.textContent);
				}

				var map = [
					["modal_attack_knight", "knight"],
					["modal_attack_target_coords_x", "targetCoordsX"],
					["modal_attack_target_coords_y", "targetCoordsY"],
					["modal_attack_supplyfilter_checkbox", "supplyfilterCheckbox"],
					["modal_attack_gold", "gold"],
					["modal_attack_rec1", "food"], // nahrung
					["modal_attack_rec2", "wood"],  // holz,
					["modal_attack_rec3", "stone"],// stein
					["modal_attack_rec4", "ore"],  // erz	
					["modal_attack_rec5", "aestone"],  // aetherstein					
				];
				for (i = 0; i < map.length; i++) {
					var elmt = ksx.tools.getElement(map[i][0], true);
					this[map[i][1]] = elmt;
				}

				this.maxGoldValue = ksx.tools.getElement("modal_attack_rec_max_gold", true).textContent;
				this.maxFoodValue = ksx.tools.getElement("modal_attack_rec_max_rec1", true).textContent;
				this.maxWoodValue = ksx.tools.getElement("modal_attack_rec_max_rec2", true).textContent;
				this.maxStoneValue = ksx.tools.getElement("modal_attack_rec_max_rec3", true).textContent;
				this.maxOreValue = ksx.tools.getElement("modal_attack_rec_max_rec4", true).textContent;
				this.maxAeStoneValue = ksx.tools.getElement("modal_attack_rec_max_rec5", true).textContent;

				this.maxUnit = ksx.tools.getElement("modal_attack_maxunt", true);
				this.maxRes = ksx.tools.getElement("modal_attack_maxres", true);

				this.getMarchType = function () {
					for (i = 1; i < 6; i++) if (ksx.tools.getElement('modal_attack_tab_' + i, true).className == 'selected') return i;
					return 0;
				};
			} catch (e) {
				GM_log("ERROR: MarchUI - " + e);
				throw e;
			}

		},

		getCityBuilding: function getCityBuilding(cityId, buildingId) {
			var b = uW.seed.buildings['city' + cityId];
			var ret = { count: 0, maxLevel: 0 };
			for (var i = 1; i < 33; i++) {
				if (b['pos' + i] && b['pos' + i][0] == buildingId) {
					++ret.count;
					if (parseInt(b['pos' + i][1]) > ret.maxLevel)
						ret.maxLevel = parseInt(b['pos' + i][1]);
				}
			}
			return ret;
		},

		getMyAlliance: function () {
			if (uW.seed.allianceDiplomacies == null || uW.seed.allianceDiplomacies.allianceName == null)
				return [0, ''+culang.mainNone+''];
			else
				return [uW.seed.allianceDiplomacies.allianceId, uW.seed.allianceDiplomacies.allianceName];
		},

		getAllianceId: function () {
			if (uW.seed.allianceDiplomacies == null || uW.seed.allianceDiplomacies.allianceName == null)
				return 0; else return uW.seed.allianceDiplomacies.allianceId;
		},

		getLanguage:function () {
			var t=ksx.tools.getElement("//div[@id='mod_untqueue']/div/span",true).textContent;
			switch (t) {
				case SR.en.koc_TroopActivity:lang='en'; // English  en
				case SR.de.koc_TroopActivity:lang='de'; // German   de
				case SR.fr.koc_TroopActivity:lang='fr'; // French   fr
				case SR.it.koc_TroopActivity:lang='it'; // Italian  it
				case SR.tr.koc_TroopActivity:lang='tr'; // Turkish  tr
				case SR.es.koc_TroopActivity:lang='es'; // Spanish  es
				case SR.se.koc_TroopActivity:lang='se'; // Swedish  se   Svenska
				case SR.nl.koc_TroopActivity:lang='nl'; // Dutch    nl   Nederlands
				default                     : return 'en';
			}
		},
		
		// works with greasmonkey, but not compatible with JScript (VS)
		// get lang (){return this.getLanguage();},
		lang: "en",

		// Power v0.6.6
		AjaxRequest: function (url, opts) {
			var headers = {
				'X-Requested-With': 'XMLHttpRequest',
				'X-Prototype-Version': '1.6.1',
				'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
			};
			var ajax = null;

//			if (DEBUG_TRACE_AJAX) logit("AJAX: " + url + "\n" + inspect(opts, 3, 1));

			if (window.XMLHttpRequest) ajax = new XMLHttpRequest();
			else ajax = new ActiveXObject("Microsoft.XMLHTTP");

			if (opts.method == null || opts.method == '') method = 'GET';
			else method = opts.method.toUpperCase();

			if (method == 'POST') {
				headers['Content-type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
			} else if (method == 'GET') {
				addUrlArgs(url, opts.parameters);
			}

			ajax.onreadystatechange = function() {
				//  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; states 0-4
				if (ajax.readyState == 4) {
					if (ajax.status >= 200 && ajax.status < 305)
						if (opts.onSuccess) opts.onSuccess(ajax);
						else if (opts.onFailure) opts.onFailure(ajax);
				} else {
					if (opts.onChange) opts.onChange(ajax);
				}
			};
			ajax.open(method, url, true); // always async!

			for (var k in headers) ajax.setRequestHeader(k, headers[k]);
			if (ksx.tools.typeOf(opts.requestHeaders) == 'object') for (var k in opts.requestHeaders) ajax.setRequestHeader(k, opts.requestHeaders[k]);

			if (method == 'POST') {
				var a = [];
				for (k in opts.parameters) a.push(k + '=' + opts.parameters[k]);
				ajax.send(a.join('&'));
			} else {
				ajax.send();
			}
		},

		// Power v0.6.6
		MyAjaxRequest: function (url, o, noRetry) {
//			if (DEBUG_TRACE) logit(" 0 myAjaxRequest: " + url + "\n" + inspect(o, 2, 1));
			var opts = uW.Object.clone(o);
			var wasSuccess = o.onSuccess;
			var wasFailure = o.onFailure;
			var retry = 0;
			var delay = 5;
			var noRetry = noRetry === true ? true : false;
			opts.onSuccess = mySuccess;
			opts.onFailure = myFailure;

//			if (DEBUG_TRACE) logit(" 1a myAjaxRequest: " + url + "\n" + inspect(o, 2, 1));
			new ksx.koc.AjaxRequest(url, opts);
			return;

			function myRetry() {
				++retry;
				new ksx.koc.AjaxRequest(url, opts);
				delay = delay * 1.25;
			}

			function myFailure() {
				var o = { };
//				if (DEBUG_TRACE) logit("myAjaxRequest.myFailure(): " + inspect(rslt, 1, 1));
				o.ok = false;
				o.errorMsg = "AJAX Communication Failure";
				wasFailure(o);
			}

			function mySuccess(msg) {
				var rslt = eval("(" + msg.responseText + ")");
				var x;
				if (rslt.ok) {
//					if (DEBUG_TRACE) logit(" 1b myAjaxRequest.mySuccess(): " + inspect(rslt, 1, 1));
					rslt.errorMsg = null; ///// !!!!!!!!!!!!!  ************
					if (rslt.updateSeed) uW.update_seed(rslt.updateSeed);
					wasSuccess(rslt);
					return;
				}
//				if (DEBUG_TRACE) logit(" 1b myAjaxRequest.mySuccess() !ok : " + inspect(rslt, 3, 1));
				rslt.errorMsg = uW.printLocalError((rslt.error_code || null), (rslt.msg || null), (rslt.feedback || null));
				if ((x = rslt.errorMsg.indexOf('<br><br>')) > 0) rslt.errorMsg = rslt.errorMsg.substr(0, x - 1);
				if (!noRetry && (rslt.error_code == 0 || rslt.error_code == 8 || rslt.error_code == 1 || rslt.error_code == 3)) {
					dialogRetry(rslt.errorMsg, delay, function() {
						myRetry();
					}, function() {
						wasSuccess(rslt);
					});
				} else {
					wasSuccess(rslt);
				}
			}
		},
		
		// Power 0.6.6
		inspect:function (obj, maxLevels, level, doFunctions) {
			var str = '', type, msg;
			if (level == null) level = 0;
			if (maxLevels == null) maxLevels = 1;
			if (maxLevels < 1) return 'Inspect Error: Levels number must be > 0';
			if (obj == null) return 'ERROR: Object is NULL\n';
			var indent = '';
			for (var i = 0; i < level; i++) indent += '  ';
			for (var property in obj) {
				try {
					type = ksx.tools.typeOf(obj[property]);
					if (doFunctions == true && (type == 'function')) {
						str += indent + '(' + type + ') ' + property + "[FUNCTION]\n";
					} else if (type != 'function') {
						str += indent + '(' + type + ') ' + property + ((obj[property] == null) ? (': null') : ('')) + ' = ' + obj[property] + "\n";
					}
					if ((type == 'object' || type == 'array') && (obj[property] != null) && (level + 1 < maxLevels)) str += inspect(obj[property], maxLevels, level + 1, doFunctions); // recurse
				} catch(err) {
					// Is there some properties in obj we can't access? Print it red.
					if (typeof(err) == 'string') msg = err;
					else if (err.message) msg = err.message;
					else if (err.description) msg = err.description;
					else msg = 'Unknown';
					str += '(Error) ' + property + ': ' + msg + "\n";
				}
			}
			str += "\n";
			return str;
		},
		
		attachXYPaste: function (xId, yId, func) {
			// thx (c) unchanged from [KoC Attack - Deutsch] 
			var x = ById(xId);
			if (!x) {
				GM_log("Buttler: Coordinate box not found!");
				return;
			}
			var attached = x.getAttribute('KOCpasteAttached');
			if (attached) return;
			x.setAttribute('maxlength', '20');

			var onchange = function () {
				var xValue = x.value.trim();
				var xI = /^\s*([0-9]+)[\s|,|-|.]+([0-9]+)/.exec(xValue);
				if (xI) {
					var y = ById(yId);
					x.value = xI[1];
					y.value = xI[2];

					if (func != undefined) func(xI[0], xI[1]);
				}
			};
			x.setAttribute('KOCpasteAttached', true);
			x.addEventListener('keyup', function () { onchange(); }, false);
			x.addEventListener('change', function () { onchange(); }, false);
		},
		
		className: "ksx.koc"
	};

	this.plugins = {className: "ksx.plugins"};
	this.compatibility = { className: "ksx.compatibility" };
	this.configuration = { className: "ksx.configuration" };
	this.className = "KSX";

	/*DEBUGCODE:*/ this.logit("Current player: " + this.koc.getPlayerName());
};

function ToolbarPlugin(ksx) {

	var macros = {
		// contains all functions, which can be called from toolbar buttons
		
		dumpSeed: function () {
			function dump(obj,path) {
				for (var o in objs) {if(o===obj) return;} objs.push(obj);
				//if(ksxDebug) GM_log("dump " + path);
				
				for (var propName in obj) {
					var propPath = path + "." + propName;
					var propValue = obj[propName];
					
					if(propValue===null) {
						s += "" + propPath +" (undefinied): null" + "\n";
						return;
					}
					var propValueType = typeof propValue;
					switch (propValueType) {
						case "function":return;
						case "object": s += "" + propPath +" ("+ propValueType +"): >>" /*+ propValue.toString().substr(0,20)*/ + "\n";break;
						default:s += "" + propPath +" ("+ propValueType +"): "+ propValue.toString() + "\n";break;
					}
				
					if(obj.propertyIsEnumerable(propName) && !(typeof propValue === "string")) {
						++ind;dump(propValue,propPath);--ind;
					}
				}
			}
			var objs = [];
			var ind = 0;
			var s = "";
			dump(uW.seed,"seed");
			//GM_log(s);
		},
		dumpThroneItems: function () {
			function dump(obj,path) {
				for (var o in objs) {if(o===obj) return;} objs.push(obj);
				//if(ksxDebug) GM_log("dump " + path);
				
				for (var propName in obj) {
					var propPath = path + "." + propName;
					var propValue = obj[propName];
					
					if(propValue===null) {
						s += "" + propPath +" (undefinied): null" + "\n";
						return;
					}
					var propValueType = typeof propValue;
					switch (propValueType) {
						case "function":return;
						case "object": s += "" + propPath +" ("+ propValueType +"): >>" /*+ propValue.toString().substr(0,20)*/ + "\n";break;
						default:s += "" + propPath +" ("+ propValueType +"): "+ propValue.toString() + "\n";break;
					}
				
					if(obj.propertyIsEnumerable(propName) && !(typeof propValue === "string")) {
						++ind;dump(propValue,propPath);--ind;
					}
				}
			}
			var objs = [];
			var ind = 0;
			var s = "";
			dump(uW.kocThroneItems,"kocThroneItems");
			dump(uW.cm.thronestats.effects,"cm.thronestats.effects");
			dump(uW.cm.thronestats.boosts,"cm.thronestats.boosts");
			
			var sEffects="";
			var aType=[];
			for(var propName in uW.cm.thronestats.effects){
				var effect = uW.cm.thronestats.effects[propName]
				sEffects += "" + propName + "\t" + effect[1] + "\t";
				for (l=0;l<effect["2"].length;l++){
					type = effect["2"][l];
					sEffects+=type+","
				}
				sEffects += "\n";
			}
			s+=sEffects;
			
			var item_number=0;
			sItems="";
			for(var n1 in uW.kocThroneItems){
				item_number++;
				item=uW.kocThroneItems[n1];
				item_level    = item.level;
				item_quality  = item.quality;
				item_type     = item.type;
				sItems+=item.name+"\n";
				for (iEffect=1;iEffect<=5;iEffect++) {
					effect_id       = item.effects["slot"+iEffect].id;
					effect_name     = uW.cm.thronestats.effects[effect_id]["1"]					
					effect_tier     = parseInt(item.effects["slot"+iEffect].tier);
					p        = uW.cm.thronestats.tiers[effect_id][effect_tier];
					effect_value    = p.base + ((item_level * item_level + item_level) * p.growth * 0.5);
					effect_isActive = iEffect<=item_quality;
					sItems+="\t"+effect_name+" "+effect_value + "%"+"\n";
				}
			}
			s+=sItems;
			
			GM_log(s);
		},

		// opens the new message dialog
		newMessage: function () {
			if(ksxDebug) GM_log("Calling ksx.plugins.Toolbar.macros.newMessage()");
			ksx.tools.douW("modal_messages(); track_chrome_btn('messages_btn'); modal_messages_compose();", true);
		},
		
		// opens the send to alliance dialog
		newMessageAtAlliance: function () {
			if(ksxDebug) GM_log("Calling ksx.plugins.Toolbar.macros.newMessageAtAlliance()");
			var doit = "getMessageWindow(" + ksx.koc.getAllianceId() + ",'Alliance Members','allianceall')";
			//if(ksxDebug) GM_log("douW "+doit);
			ksx.tools.douW(doit, true);
		},
		
		// opens the march dialog
		newMarch: function (marchType, x, y, troops, res) { ksx.plugins.MarchExtender.march.show(marchType, x, y, troops, res); },

		// template: function(){},

		className: "Macros"
	};
	this.macros = macros;

	this.initUI = function (thisPlugin) {
		if (ksxDebug) GM_log("Calling ToolbarPlugin.initUI");

		var fc = document.body.firstChild;

		var tbDiv = document.createElement('div');
		tbDiv.id = "ksx_ToolbarPlugin_ToolbarContainer";
		tbDiv.setAttribute("style", "line-height: 22px; font-size: small; text-align: left; border-bottom: 1px solid silver; height: 24px; width: 740px; background: none repeat scroll 0% 0% "+Colors.scToolbarBG+"; ");
		// div.style.width = '772px';
		// div.style.width = '1100px'; //+ Chat Rechts

		var lines = 1;
		for (var i = 0; i < ksx.configuration.toolbar.items.length; i++) {
			var item = ksx.configuration.toolbar.items[i];
			if (!item) continue; //skip empty item
			if (ksxDebug) GM_log("Create toolbar item: " + item);
			switch (item[0].toLowerCase()) {
				case "button": tbDiv.appendChild(ksx.Builder.ToolbarButton(item[2], item[3], item[1])); break;
				case "label": tbDiv.appendChild(ksx.Builder.Span(item[2])); break;
				case "html": tbDiv.appendChild(ksx.Builder.Span(item[1])); break;
				case "linebreak": lines++; tbDiv.appendChild(document.createElement("br")); break; //TODO 
				//				case "popup": break; //TODO              
				case "separator": tbDiv.appendChild(ksx.Builder.Span(" | ")); break;
				default: break;
			}
		}

		tbDiv.style.height = (lines * 22 + 4) + 'px';

		var toolbarsPanelDiv = ById("ksx_ToolbarPlugin_ToolbarsPanel");
		if (toolbarsPanelDiv == null) {
			toolbarsPanelDiv = document.createElement('div');
			toolbarsPanelDiv.id = "ksx_ToolbarPlugin_ToolbarsPanel";
			toolbarsPanelDiv.setAttribute("style", "margin: 1px 0pt 0pt 10px;");
			document.body.insertBefore(toolbarsPanelDiv, document.body.firstChild);
		}

		toolbarsPanelDiv.appendChild(tbDiv);
	};

	this.addToolbarItem = function(item) {
		var div = ksx.tools.getElement("ksx_ToolbarPlugin_ToolbarContainer");
		switch (item[0].toLowerCase()) {
			case "button": div.appendChild(ksx.Builder.BlueButton(item[1], item[2])); break;
			case "label" : div.appendChild(ksx.Builder.Span(item[1])); break;
			case "html"  : div.appendChild(ksx.Builder.Span(item[1])); break;
			default: break;
		}
	};

	this.initUI(this);
}

function PowerToolbarPlugin(ksx) {
	
	this.macros = { className: "PowerToolbarPlugin+Macros" };

	this.atSyncButtonClick = function (evt) {
		if (ksxDebug) GM_log("PowerToolbarPlugin.atSyncButtonClick");

		var t = ksx.tools.findParentByTagName(evt.target, "A", true);
		if (!t) { GM_log("Element for event not found!"); return; }

		var id = t.getAttribute("id");
		if (!id) { GM_log("ERROR: Element has no id!"); return; }
		for (var i = 0; i < ksx.configuration.powertoolbar.syncButtons.length; i++) {
			var cfg = ksx.configuration.powertoolbar.syncButtons[i];
			if (cfg[0] === id) {
				if(cfg[2].substr(0,2)=="M:"){
					eval(cfg[2].substring(2,cfg[2].length));
				} else {
					var pbButton = ById(cfg[1]);
					if (!pbButton) { GM_log("ERROR: Element not found! '" + cfg[1] + "'"); return; }
					if (ksxDebug) GM_log("Click: " + cfg[1]);
					ksx.tools.click(pbButton);
				}
				return;
			}
		}
		GM_log("ERROR: Config not found! " + id); return;
	};

	this.updateButtons = function () {
		for (var i = 0; i < ksx.configuration.powertoolbar.syncButtons.length; i++) {
			var cfg = ksx.configuration.powertoolbar.syncButtons[i];
			var ksxpbButton = ById(cfg[0]);
			if (ksxpbButton) {
				if(cfg[1].substr(0,2)=="P:"){
					b=eval(cfg[1].substring(2,cfg[1].length));
					ksx.Builder.setToolbarCheckButton(ksxpbButton, b);
				} else {
					var pbButton = ById(cfg[1]);
					if (pbButton) {
						ksx.Builder.setToolbarCheckButton(ksxpbButton, String(pbButton[cfg[2]]).search(cfg[3]) != -1);
					} else {
						ksx.Builder.setToolbarCheckButton(ksxpbButton, null);
					}
				}
			}
		}
	};

	this.initUI = function (thisPlugin) {
		if (ksxDebug) GM_log("Calling PowerToolbarPlugin.initUI");

		var tbDiv = document.createElement('div');
		tbDiv.id = "ksx_PowerToolbarPlugin_ToolbarContainer";
		tbDiv.setAttribute("style", "line-height: 22px; font-size: small; text-align: left;  height: 24px; width: 750px; background: none repeat scroll 0% 0%  "+Colors.scToolbarBG2+";");
		// div.style.width = '772px';
		// div.style.width = '1100px'; //+ Chat Rechts

		var lines = 1;
		for (var i = 0; i < ksx.configuration.powertoolbar.items.length; i++) {
			var item = ksx.configuration.powertoolbar.items[i];
			if (!item) continue; //skip empty item
			if (ksxDebug) GM_log("Create toolbar item: " + item);
			switch (item[0].toLowerCase()) {
				case "button": tbDiv.appendChild(ksx.Builder.ToolbarButton(item[2], item[3], item[1])); break;
				case "label": tbDiv.appendChild(ksx.Builder.Span(item[2])); break;
				case "html": tbDiv.appendChild(ksx.Builder.Span(item[1])); break;
				case "linebreak": lines++; tbDiv.appendChild(document.createElement("br")); break; //TODO 
				//				case "popup": break; //TODO             
				case "separator": tbDiv.appendChild(ksx.Builder.Span(" | ")); break;
				default: break;
			}
		}
		tbDiv.style.height = (lines * 22 + 4) + 'px';

		var toolbarsPanelDiv = ById("ksx_ToolbarPlugin_ToolbarsPanel");
		toolbarsPanelDiv.appendChild(tbDiv);
	};

	this.addToolbarItem = function (item) {
		var div = ksx.tools.getElement("ksx_PowerToolbarPlugin_ToolbarContainer");
		switch (item[0].toLowerCase()) {
			case "button": div.appendChild(ksx.Builder.BlueButton(item[1], item[2])); break;
			case "label": div.appendChild(ksx.Builder.Span(item[1])); break;
			case "html": div.appendChild(ksx.Builder.Span(item[1])); break;
			default: break;
		}
	};

	this.updateTimer = function () {
		ksx.plugins.PowerToolbar.updateButtons();
	};

	this.initSync = function (thisPlugin) {
		for (var i = 0; i < ksx.configuration.powertoolbar.syncButtons.length; i++) {
			var cfg = ksx.configuration.powertoolbar.syncButtons[i];
			//GM_log("Init toolbarsync: " + cfg[0] + " " + cfg[1]);
			var tbButton = ById(cfg[0]);
			if (!tbButton) { GM_log("Element not found! '" + cfg[0] + "'"); }
			if (tbButton) { tbButton.addEventListener("click", thisPlugin.atSyncButtonClick, false); }
		}
	};
	this.className = "PowerToolbarPlugin";
	this.initUI(this);
	this.initSync(this);
	window.setInterval(this.updateTimer, 1000);
}

function ChatMonitorPlugin(ksx) {

	this.infoTokens = SR.getArray("ksx_ChatMonitor_InfoTokens",LangOptions.culang); //Spam vom KoC Power z.B.
	this.attackTokens = SR.getArray("ksx_ChatMonitor_AttackTokens",LangOptions.culang);

	this.hooks = [];

	this.AddHook = function (fnc) {
		this.hooks.push(fnc);
	};

	this.Filter = function (name, tokens, conditions, fnc) {
		this.name = name;
		this.tokens = tokens || [];
		this.conditions = conditions || {};
		this.fnc = fnc;
	};

	this.MsgDivWrapper = function (msgdiv) {
		this.msgdiv = msgdiv;
		this.msgType = "unknown"; this.isAlliance = false; this.isDirect = false; this.isNoAlliance = false; this.isGlobal = false;
		if (msgdiv.getAttribute("class") == "chatwrap clearfix") { this.msgType = "alliance"; this.isAlliance = true; }
		else if (msgdiv.getAttribute("class") == "chatwrap clearfix direct") { this.msgType = "direct"; this.isDirect = true; }
		else if (msgdiv.getAttribute("class") == "chatwrap clearfix noalliance") { this.msgType = "noalliance"; this.isNoAlliance = true; }
		else if (msgdiv.getAttribute("class") == "chatwrap clearfix global") { this.msgType = "global"; this.isGlobal = true; }

		if (!this.isNoAlliance) {
			var playerName = ksx.koc.getPlayerName();
			this.img = msgdiv.childNodes[0];
			this.contentDiv = msgdiv.childNodes[1];
			this.infoDiv = msgdiv.childNodes[1].childNodes[0];
			this.whoA = msgdiv.childNodes[1].childNodes[0].childNodes[0];
			this.saysB = msgdiv.childNodes[1].childNodes[0].childNodes[1];
			this.timeSpan = msgdiv.childNodes[1].childNodes[0].childNodes[3];
			this.clearfixDiv = msgdiv.childNodes[1].childNodes[1];
			this.tx = msgdiv.childNodes[1].childNodes[1].childNodes[0];

			this.isOwnEntry = (this.whoA.textContent == playerName);
			this.msgtxt = this.tx.textContent;
		} else {

		}
	};

	this.filters = [];

	//#region Feature: "Cheat Zeit Korrektur"
	this.chatEntryTimeCorrection = function (chatEntry) {
		//if(ksxDebug) GM_log("enableTimeCorrection: " + enableTimeCorrection);
		if (chatEntry.msgdiv.getAttribute("class") != "chatwrap clearfix" && chatEntry.msgdiv.getAttribute("class") != "chatwrap clearfix direct") return;

		var timeOffset = 9; // TODO read from Config
		var chhmm = ksx.tools.getElement("kochead_time").innerHTML.split(":");
		var cmmm = (60 * chhmm[0]) + (1 * chhmm[1]);

		var timeSpan = chatEntry.msgdiv.childNodes[1].childNodes[0].childNodes[3];
		var hhmm = timeSpan.innerHTML.split(":");
		var hh = (1 * hhmm[0]);
		var mmm = hh * 60 + (1 * hhmm[1]);

		if (Math.abs(cmmm - mmm) > 2) {
			hh += timeOffset; if (hh >= 24) hh -= 24; if (hh < 10) hh = "0" + hh;
			var newTime = hh + ":" + hhmm[1];
			//if(ksxDebug) GM_log("Chat entry: time correction: " + timeSpan.innerHTML + " + Offset " + timeOffset + "h = " + newTime);
			timeSpan.innerHTML = newTime;
		}

	};
	//#endregion
	
	this.scanChatItem = function (chatEntry, filter) {
		/*DEBUGCODE:*/if (ksxDebug) GM_log("ChatMonitorPlugin.scanChatItem()");
		
		var infoStyle ='background-color: #ffffff';
	// if (Options.pdxBackgroundStyle=="pdxKoCOld" /* && Options.pbChatOnRight==true*/ ) {
		// infoStyle = "background: " + ksx.configuration.chat.backgrounds.InfoBackground;
	// }else{
		// infoStyle = "background-color: "+Colors.SpamBackground+"; -moz-box-shadow: 0 0 3px 2px "+Colors.SpamBackground+"; padding:8px; margin-Bottom:3px; -moz-border-radius:3px;";
		// funktioniert nicht
		// chatEntry.msgdiv.style.linkColor = '#333 !important'; //TODO PDX do it in style
	// }
		
		var infoTokens = ksx.plugins.ChatMonitor.infoTokens;
//		var attackTokens = ksx.plugins.ChatMonitor.attackTokens; //KSX allways in [Power]

		if (chatEntry.token0 == infoTokens[0]) {
			/*DEBUGCODE:*/if (ksxDebug) GM_log("INFO token found");
			chatEntry.msgdiv.setAttribute("style", infoStyle);
			return true;
		}
//KSX allways in [Power]
//		  else if (chatEntry.token0 == attackTokens[0] && chatEntry.isOwnEntry) {
//			/*DEBUGCODE:*///if (ksxDebug) GM_log("ATTACK (own) token found");
//			var ownAttackStyle = "background: " + ksx.configuration.chat.backgrounds.OwnAttackBackground;
//			chatEntry.msgdiv.setAttribute("style", ownAttackStyle);
//			return true;
//		} else if (chatEntry.token0 == attackTokens[0] && !chatEntry.isOwnEntry) {
//			/*DEBUGCODE:*/ //if (ksxDebug) GM_log("ATTACK (alliance) token found");
//          var allyAttackStyle = "background: " + ksx.configuration.chat.backgrounds.AllyAttackBackground;
//			chatEntry.msgdiv.setAttribute("style", allyAttackStyle);
//			return true;
//		}
		return false;
	};

	this.scanAllianceChat = function () {
		/*DEBUGCODE:*/if(ksxDebug) GM_log("ChatMonitorPlugin.scanAllianceChat");

		function setEntryHandled(info) {
			if(typeof(info)!=="unspecified" && info!==null) info=" ("+info+")";
			msgdiv.innerHTML += "<div style='display:none'>Entry processed by ChatMonitorPlugin"+info+"</div>";
		}
// TODO KSX modCommList2 is undefined on startup
		var modCommList2 = ksx.tools.getElement("mod_comm_list2");
		for (var i = 0; i < modCommList2.childNodes.length; i++) {
			var msgdiv = modCommList2.childNodes[i];
			var t=msgdiv.textContent;
			if (t.indexOf("Entry processed by ChatMonitorPlugin")>=0) return; //allready handled item found => exit loop
			var chatEntry = new ksx.plugins.ChatMonitor.MsgDivWrapper(msgdiv);

			if (chatEntry.isNoAlliance) { setEntryHandled(); continue; }

			//#region Feature: "Cheat Zeit Korrektur"
			if (ksx.configuration.chat.enableTimeCorrection) {
				ksx.plugins.ChatMonitor.chatEntryTimeCorrection(chatEntry, null);
			}
			//#endregion

			var token = null; var token0 = null; var filter = null;
			for (var k = 0; k < ksx.plugins.ChatMonitor.filters.length; k++) {
				token = null; token0 = null; filter=null;
				var f = ksx.plugins.ChatMonitor.filters[k];
				// /*DEBUG*/ GM_log("Checking filter: [" + k + "].name: " + f.name);
				for (var j = 0; j < f.tokens.length; j++) {
					var t = f.tokens[j];
					var isRegExp = (t.match(/^.*\/[gim]*$/)) != null;
					//GM_log("\"" + t + "\" is regexp " + isRegExp);
					if (isRegExp) var tg = t.match(/[gim]*$/);
					if (isRegExp) t = t.replace(/^\//, "").replace(/\/[gim]*$/, "").replace("\\", "\\\\");
					//if (isRegExp) GM_log("new RegExp(\"" + (t || "") + "\",\"" + (tg || "") + "\")");
					if (isRegExp) {
						var regexp = new RegExp((t || ""), (tg || ""));
						var match = chatEntry.msgtxt.match(regexp);
						if (match) {
							filter=f;
							token = f.tokens[j];
							token0 = f.tokens[0];
							if(ksxDebug) GM_log("match: " + match + " in \"" + chatEntry.msgtxt +"\"");
						} else {
							if(ksxDebug) GM_log("No match in \"" + chatEntry.msgtxt + "\"");
						}
					} else if (chatEntry.msgtxt.indexOf(t) == 0) {
						filter = f;
						token = f.tokens[j];
						token0 = f.tokens[0];
					}
//					if (typeof t === "string" && chatEntry.msgtxt.indexOf(t) == 0) {
//						token = filter.tokens[j];
//						token0 = filter.tokens[0];
//					} else if (t instanceof RegExp && chatEntry.msgtxt.match(t) != null) {
//						token = filter.tokens[j];
//						token0 = filter.tokens[0];
//					}
					if (token != null) break;
				}
				if (token != null) break;
			}
			if (!token) {
				setEntryHandled();
				//if(thisPlugIn.logFilter) GM_log("No token found. filters: (" + ksx.plugins.ChatMonitor.filters.length + ")"); 
				continue;
			}
			chatEntry.token0 = token0;
			chatEntry.token = token;

			/*DEBUGCODE:*/if (ksxDebug) GM_log("Chat token found: " + chatEntry.token + " isOwnEntry: " + chatEntry.isOwnEntry + " context: " + chatEntry.msgType);

			var entryHandled = false;
			for (var k = 0; k < ksx.plugins.ChatMonitor.filters.length; k++) {
				var f = ksx.plugins.ChatMonitor.filters[k];
				//GM_log("Checking filter: [" + k + "].name: " + f.name + " tokens: " + f.tokens + " isOwnEntry: " + f.conditions.isOwnEntry);
				if (!f.tokens) continue;
				if (f.tokens[0] != token0) continue;
				if (!(typeof f.conditions.isOwnEntry === "undefined") && !(f.conditions.isOwnEntry === null) && f.conditions.isOwnEntry != chatEntry.isOwnEntry) continue;

				entryHandled = f.fnc(chatEntry, f);
				if (entryHandled) { entryHandled = true; setEntryHandled(); return; }
			}

			//special case, no token, must be allways the last
			if (entryHandled && chatEntry.isOwnEntry) {
				(function () {
					var ownStyle = "color:#FFF; background-color: #333; -moz-box-shadow: 0 0 3px 2px #333; padding:8px; margin-Bottom:3px; -moz-border-radius:3px;";
					chatEntry.msgdiv.setAttribute("style", ownStyle);
				})();
				setEntryHandled();
				continue;
			}

			setEntryHandled();
		}
	};
	
	var filters = this.filters;
	var Filter = this.Filter;
	filters.push(new Filter('infoTokens', this.infoTokens, {}, this.scanChatItem));
//	filters.push(new Filter('attackTokens', this.attackTokens, {}, this.scanChatItem)); //allways in [Power]

	if (ksxDebug) GM_log("setInterval scanAllianceChat");
	window.setInterval(this.scanAllianceChat, 5000);
}

function ResourceRequestPlugin(ksx) {
	//REQUIRES ChatMonitorPlugin, MarchExtenderPlugin
	var thisPlugin = this;
	this.className = "ResourceRequestPlugin";
	
	var lang = LangOptions.culang;//ksx.koc.lang
	var acknowledgeTokens = SR.getArray("ksx_ResourceRequest_AcknowledgeTokens",lang);
	var requestTokens     = SR.getArray("ksx_ResourceRequest_RequestTokens"    ,lang);
	var deliveryTokens    = SR.getArray("ksx_ResourceRequest_DeliveryTokens"   ,lang);
	var foodLowTokens     = SR.getArray("ksx_ResourceRequest_FoodLowTokens"    ,lang);
	
	var atResourceRequestClick = function () {
		if(ksxDebug) GM_log("ResourceRequestPlugin.atResourceRequestClick");
		//var ksx = uW.ksx; if (ksx == null) throw "ksx is null!";

		var rrDestination = ksx.tools.getElement("rrDestination");
		var rrGoldAmount  = ksx.tools.getElement("rrGoldAmount");
		var rrFoodAmount  = ksx.tools.getElement("rrFoodAmount");
		var rrWoodAmount  = ksx.tools.getElement("rrWoodAmount");
		var rrStoneAmount = ksx.tools.getElement("rrStoneAmount");
		var rrOreAmount   = ksx.tools.getElement("rrOreAmount");
		var rrAetherAmount   = ksx.tools.getElement("rrAetherAmount");

		var req = ksx.plugins.ResourceRequest.CurrentRequest;

		req.Version = "2";
		req.Destination = rrDestination.value.toLowerCase().replace(/;|-|\//, ",").replace("-", ",").replace("/", ",").replace(/\s+/g, "");
		//TODO KSX multilang
		req.Gold = rrGoldAmount.value.toLowerCase().replace(" ", "").replace("mille", "M").replace("kk", "M").replace("mio", "M").replace("mrd", "G");
		req.Food = rrFoodAmount.value.toLowerCase().replace(" ", "").replace("mille", "M").replace("kk", "M").replace("mio", "M").replace("mrd", "G");
		req.Wood = rrWoodAmount.value.toLowerCase().replace(" ", "").replace("mille", "M").replace("kk", "M").replace("mio", "M").replace("mrd", "G");
		req.Stone = rrStoneAmount.value.toLowerCase().replace(" ", "").replace("mille", "M").replace("kk", "M").replace("mio", "M").replace("mrd", "G");
		req.Ore = rrOreAmount.value.toLowerCase().replace(" ", "").replace("mille", "M").replace("kk", "M").replace("mio", "M").replace("mrd", "G");
		req.Aether = rrAetherAmount.value.toLowerCase().replace(" ", "").replace("mille", "M").replace("kk", "M").replace("mio", "M").replace("mrd", "G");

		var pers = ksx.JSON.stringify(req);
		//ksx.logit("save: "+pers);
		GM_setValue("ResourceRequest_" + ksx.koc.getServerId(), pers);

		var modCommInput = ksx.tools.getElement("mod_comm_input");
		if (modCommInput == null) { alert("mod_comm_input not found!"); return; }

		// compose ResourceRequest in current language
		// TODO culang.aetherstones
		var sA = "";
		if (req.Gold  .length > 0 && req.Gold   != 0) sA = sA + (sA.length > 0 ? " + " : "") + uW.g_js_strings.commonstr.gold    + " " + req.Gold;
		if (req.Food  .length > 0 && req.Food   != 0) sA = sA + (sA.length > 0 ? " + " : "") + uW.g_js_strings.commonstr.food    + " " + req.Food;
		if (req.Wood  .length > 0 && req.Wood   != 0) sA = sA + (sA.length > 0 ? " + " : "") + uW.g_js_strings.commonstr.wood    + " " + req.Wood;
		if (req.Stone .length > 0 && req.Stone  != 0) sA = sA + (sA.length > 0 ? " + " : "") + uW.g_js_strings.commonstr.stone   + " " + req.Stone;
		if (req.Ore   .length > 0 && req.Ore    != 0) sA = sA + (sA.length > 0 ? " + " : "") + uW.g_js_strings.commonstr.ore     + " " + req.Ore;
		if (req.Aether.length > 0 && req.Aether != 0) sA = sA + (sA.length > 0 ? " + " : "") + uW.g_js_strings.commonstr.aetherstone + " " + req.Aether;
		
		//if(sA.length==0) return;
		var s = "/a " + requestTokens[0] + " " + req.Destination + " " + sA;
		//ksx.logit("Send: "+s);
		
		ksx.tools.type(modCommInput, s);
		ksx.tools.click(modCommInput.nextSibling);

		ksx.tools.getElement("rrContainer").style.display = "none";
		ksx.tools.getElement("//*[@class='comm_body comm_global']").style.display = "";
	};
	this.atResourceRequestClick = atResourceRequestClick;

	this.CurrentRequest = {
		/* [3 - 2012-03-12]
		 * NEW field 'Aether'
		 */
		Version: "3",
		Destination: "xxx,yyy",
		Gold: "",
		Food: "",
		Wood: "",
		Stone: "",
		Ore: "100mio",
		Aether: ""
	};

	var atShowResourceRequest = function () {
		/*DEBUGCODE:*/if(ksxDebug) GM_log("ResourceRequestPlugin.atShowResourceRequest");
		ksx.tools.getElement("rrContainer").style.display = "";
		ksx.tools.getElement("//*[@class='comm_body comm_global']").style.display = "";
	};
	this.atShowResourceRequest = atShowResourceRequest;

	var atCloseResourceRequest = function () {
		/*DEBUGCODE:*/if(ksxDebug) GM_log("ResourceRequestPlugin.atCloseResourceRequest");
		ksx.tools.getElement("rrContainer").style.display = "none";
		ksx.tools.getElement("//*[@class='comm_body comm_global']").style.display = "";
	};
	this.atCloseResourceRequest = atCloseResourceRequest;

	this.initUI = function () {
		/*DEBUGCODE:*//*if (ksxDebug)*/GM_log("ResourceRequestPlugin.initUI");

		var kocCommTabs = ksx.tools.getElement("comm_tabs");
		if (!kocCommTabs) { throw "Element 'comm_tabs' not found! Maybe KoC has some changes."; }
		var modComm = ksx.tools.getElement("//*[@class='mod_comm']");
		if (!modComm) { throw "Element 'mod_comm' not found! Maybe KoC has some changes."; }

		// Append the "Anfrage" Tab resourceRequestButtonTitle
		var btn = ksx.Builder.ComTabButton(culang.ksx_KoCButtler_ResourceRequest_ButtonTitle, "ksx.plugins.ResourceRequest.atShowResourceRequest();return false;");
		kocCommTabs.appendChild(btn);

		//INFO IMGfood, IMGwood, IMGxxx are defined in images.js
		// Append the "Resource-Request" form
		var htmlTemplate ="";
		if (Options.pbChatOnRight==true) {
			htmlTemplate = "<div id='rrContainer' style='padding: 5px; text-align: center; -moz-border-radius:3px; border:1px inset #FFF; -moz-box-shadow: 0 0 3px 3px #141516;  background-image:url("+IMGksBG+"); position: relative; top:-80px; height: 290px; margin-left: 50px; overflow-x: hidden; overflow-y: hidden;  width: 220px;'><table class=pdxTab style='background-image:url("+IMGksBG+"); color=#FFFFFF; width: 100%'><tr><td><span style='font-weight: bold; color: #FFFFFF;'>{%Caption%}</span></td><td style='text-align: right'><a href='#' onclick='ksx.plugins.ResourceRequest.atCloseResourceRequest();return false;'><img src='"+IMGkocClose+"' alt='X' /></a></td></tr></table><table style='color:#FFF;' class=pdxTab><tbody><tr align='center'><td><img src='"+IMGfood30+"'></td><td>{%Amount%}:<input id='rrFoodAmount' type='text' value='0' maxlength='11' size='11'></td></tr><tr align='center'><td><img src='"+IMGwood30+"'></td><td>{%Amount%}:<input id='rrWoodAmount' type='text' value='0' maxlength='11' size='11'></td></tr><tr align='center'><td><img src='"+IMGstone30+"'></td><td>{%Amount%}:<input id='rrStoneAmount' type='text' value='0' maxlength='11' size='11'></td></tr><tr align='center'><td><img src='"+IMGiron30+"'></td><td>{%Amount%}:<input id='rrOreAmount' type='text' value='0' maxlength='11' size='11'></td></tr><tr align='center'><td><img src='"+IMGgold30+"'></td><td>{%Amount%}:<input id='rrGoldAmount' type='text' value='0' maxlength='11' size='11'></td></tr><tr align='center'><td><img src='"+IMGastone30+"'></td><td>{%Amount%}:<input id='rrAetherAmount' type='text' value='0' maxlength='11' size='11'></td></tr></tbody></table><div style='margin-bottom: 10px; display: none'><span id='rrCityTo'><input id='rrTraderTo_0' class='castleBut castleButNon' type='submit' value='1'><input id='rrTraderTo_1' class='castleBut castleButNon' type='submit' value='2'><input id='rrTraderTo_2' class='castleBut castleButNon' type='submit' value='3'><input id='rrTraderTo_3' class='castleBut castleButNon' type='submit' value='4'><input id='rrTraderTo_4' class='castleBut castleButNon' type='submit' value='5'><input id='rrTraderTo_5' class='castleBut castleButNon' type='submit' value='6'><input id='rrTraderTo_6' class='castleBut castleButNon' type='submit' value='7'><span id='rrTraderToCityName' style='display: inline-block; width: 85px; font-weight: bold;'></span></span></div><div style='color:#FFF;'>{%Destination%} (X,Y):<input id='rrDestination' type='text' maxlength='7' size='7'></div><br/><span><a class='button20' onclick='ksx.plugins.ResourceRequest.atResourceRequestClick();return false;'><span>{%SendRequest%}</span></a></span></div>";
		} else if (Options.pbChatOnRight==false) {
			htmlTemplate = "<div id='rrContainer' style='padding: 5px; text-align: center; -moz-border-radius:3px; border:1px inset #FFF; -moz-box-shadow: 0 0 3px 3px #141516;  background-image:url("+IMGksBG+"); position: relative; top:-310px; height: 290px; margin-left: 355px; overflow-x: hidden; overflow-y: hidden;  width: 220px; z-index:2000000;'><table class=pdxTab style='background-image:url("+IMGksBG+"); color=#FFFFFF; width: 100%'><tr><td><span style='font-weight: bold; color: #FFFFFF;'>{%Caption%}</span></td><td style='text-align: right'><a href='#' onclick='ksx.plugins.ResourceRequest.atCloseResourceRequest();return false;'><img src='"+IMGkocClose+"' alt='X' /></a></td></tr></table><table style='color:#FFF;' class=pdxTab><tbody><tr align='center'><td><img src='"+IMGfood30+"'></td><td>{%Amount%}:<input id='rrFoodAmount' type='text' value='0' maxlength='11' size='11'></td></tr><tr align='center'><td><img src='"+IMGwood30+"'></td><td>{%Amount%}:<input id='rrWoodAmount' type='text' value='0' maxlength='11' size='11'></td></tr><tr align='center'><td><img src='"+IMGstone30+"'></td><td>{%Amount%}:<input id='rrStoneAmount' type='text' value='0' maxlength='11' size='11'></td></tr><tr align='center'><td><img src='"+IMGiron30+"'></td><td>{%Amount%}:<input id='rrOreAmount' type='text' value='0' maxlength='11' size='11'></td></tr><tr align='center'><td><img src='"+IMGgold30+"'></td><td>{%Amount%}:<input id='rrGoldAmount' type='text' value='0' maxlength='11' size='11'></td></tr><tr align='center'><td><img src='"+IMGastone30+"'></td><td>{%Amount%}:<input id='rrAetherAmount' type='text' value='0' maxlength='11' size='11'></td></tr></tbody></table><div style='margin-bottom: 10px; display: none'><span id='rrCityTo'><input id='rrTraderTo_0' class='castleBut castleButNon' type='submit' value='1'><input id='rrTraderTo_1' class='castleBut castleButNon' type='submit' value='2'><input id='rrTraderTo_2' class='castleBut castleButNon' type='submit' value='3'><input id='rrTraderTo_3' class='castleBut castleButNon' type='submit' value='4'><input id='rrTraderTo_4' class='castleBut castleButNon' type='submit' value='5'><input id='rrTraderTo_5' class='castleBut castleButNon' type='submit' value='6'><input id='rrTraderTo_6' class='castleBut castleButNon' type='submit' value='7'><span id='rrTraderToCityName' style='display: inline-block; width: 85px; font-weight: bold;'></span></span></div><div style='color:#FFF;'>{%Destination%} (X,Y):<input id='rrDestination' type='text' maxlength='7' size='7'></div><br/><span><a class='button20' onclick='ksx.plugins.ResourceRequest.atResourceRequestClick();return false;'><span>{%SendRequest%}</span></a></span></div>";
		}
		htmlTemplate=htmlTemplate.replace(/{%Caption%}/g,culang.ksx_KoCButtler_ResourceRequest_UICaption);
		htmlTemplate=htmlTemplate.replace(/{%Destination%}/g,culang.ksx_KoCButtler_ResourceRequest_UIDestination);
		htmlTemplate=htmlTemplate.replace(/{%Amount%}/g,culang.ksx_KoCButtler_ResourceRequest_UIAmount);
		htmlTemplate=htmlTemplate.replace(/{%SendRequest%}/g,culang.ksx_KoCButtler_ResourceRequest_UISendRequest);
		var div = ksx.Builder.Element("div", htmlTemplate);
		div.setAttribute("id", "rrContainer"); //Workaround id from template is not pressent!?
		div.style.display = "none"; // hide on init
		modComm.appendChild(div);

		var s = GM_getValue("ResourceRequest_" + ksx.koc.getServerId());
		// GM_log("Load ResourceRequest:" + s);

		var rrDestination = ksx.tools.getElement("rrDestination");
		var rrGoldAmount = ksx.tools.getElement("rrGoldAmount");
		var rrFoodAmount = ksx.tools.getElement("rrFoodAmount");
		var rrWoodAmount = ksx.tools.getElement("rrWoodAmount");
		var rrStoneAmount = ksx.tools.getElement("rrStoneAmount");
		var rrOreAmount = ksx.tools.getElement("rrOreAmount");
		var rrAetherAmount = ksx.tools.getElement("rrAetherAmount");

		if (s != null) {
			var rr = ksx.JSON.parse(s);
			if (ksxDebug) GM_log("Output: " + typeof (rr.ksxVersion));
			if (rr.ksxVersion == "3") {
				rrDestination.value = rr.Destination;
				rrGoldAmount.value = rr.Gold;
				rrFoodAmount.value = rr.Food;
				rrWoodAmount.value = rr.Wood;
				rrStoneAmount.value = rr.Stone;
				rrOreAmount.value = rr.Ore;
				rrAtherAmount.value = rr.Aether;
			} else if (rr.ksxVersion == "2") {
				rrDestination.value = rr.Destination;
				rrGoldAmount.value = rr.Gold;
				rrFoodAmount.value = rr.Food;
				rrWoodAmount.value = rr.Wood;
				rrStoneAmount.value = rr.Stone;
				rrOreAmount.value = rr.Ore;
				rrAtherAmount.value = "";
			} else {
				rrDestination.value = "xxx,yyy";
				rrGoldAmount.value = "";
				rrFoodAmount.value = "";
				rrWoodAmount.value = "";
				rrStoneAmount.value = "";
				rrOreAmount.value = "100mio";
				rrAetherAmount.value = "";				
			}
		} else {
			rrDestination.value = "xxx,yyy";
			rrGoldAmount.value = "";
			rrFoodAmount.value = "";
			rrWoodAmount.value = "";
			rrStoneAmount.value = "";
			rrOreAmount.value = "100mio";
			rrAetherAmount.value = "";	
		}
	};

	this.atRequestEntry = function(msg, filter) { // requestTokens && !isOwnEntry
		/*DEBUGCODE:*/if (ksxDebug) GM_log("REQUEST token found");
		
		var tReqR = msg.msgtxt;
		var t1R = tReqR.indexOf(msg.token);
		tReqR = tReqR.substring(t1R, tReqR.length);
		var t2R = tReqR.indexOf("'");
		if (t2R >= 0) tReqR = tReqR.substr(0, t2R);

		var tAck = tReqR.replace(msg.token, acknowledgeTokens[0]);
		var cA = "var chat = document.getElementById('mod_comm_input'); chat.value = '" + tAck + "';chat.focus(); return false;";

		var actiondiv = document.createElement('div');
		actiondiv.setAttribute("style", "padding: 0 0 0 30px;");
		actiondiv.appendChild(ksx.Builder.GreenButton(culang.ksx_KoCButtler_ResourceRequest_AckButtonTitle, cA));
		msg.msgdiv.appendChild(actiondiv);
		
		var reqStyle = "background: " + ksx.configuration.chat.backgrounds.RequestItemBackground;

		msg.msgdiv.setAttribute("style", reqStyle);
		return true;
	};
	
	this.atOwnAcknowledgeEntry = function (msg, filter) {
		/*DEBUGCODE:*/if (ksxDebug) GM_log("ACKNOWLEDGE token found");
		
		var tAckM = msg.msgtxt;
		var t1A = tAckM.indexOf(msg.token);
		tAckM = tAckM.substring(t1A, tAckM.length);
		var t2A = tAckM.indexOf("'");
		if (t2A >= 0) tAckM = tAckM.substr(0, t2A);

		var goldAmount = 0;
		var foodAmount = 0;
		var woodAmount = 0;
		var stoneAmount = 0;
		var oreAmount = 0;
		var aetherAmount = 0;
		var x; var y;

		var xyPattern = /([0-9]{1,3})\s*(,|-)\s*([0-9]{1,3})/;
		var match = xyPattern.exec(msg.msgtxt);
		if (match === null) return false;
		x = match[1]; y = match[3];

		//TODO KSX multilang
		var pattern = /(Aethersteine|Aetherstein|Aetherstones|Aetherstone|Nahrung|Futter|Lebensmittel|Steaks|Beeren|Food|Erz|Ore|Holz|Wood|Steine|Stein|Stone|Gold)\s*([0-9]+)(mio|mrd|bio|M|G|T|kkkk|kkk|kk|k)/gi;
		while (match = pattern.exec(msg.msgtxt)) {
			var res = match[1];
			var amount = match[2];
			var unit = match[3];
			var amountB;
			switch (unit.toLowerCase()) {
				case "k": amountB = amount * 1000; break;
				case "m": case "mio": case "kk": amountB = amount * 1000000; break;
				case "g": case "mrd": case "kkk": amountB = amount * 1000000000; break;
				case "t": case "bio": case "kkkk": amountB = amount * 1000000000000; break;
				default: amountB = amount * 1;
			}

			switch (res.toLowerCase()) {
				case "gold":                                goldAmount   = amountB; break;
				case "nahrung": case "futter": case "lebensmittel": case "steaks": case "beeren": case "food": foodAmount   = amountB; break;
				case "holz": case "wood":                   woodAmount   = amountB; break;
				case "steine": case "stein": case "stone":  stoneAmount  = amountB; break;
				case "erz": case "ore":                     oreAmount    = amountB; break;
				case "aethersteine": case "aetherstones": case "aetherstein": case "aetherstone":   aetherAmount = amountB; break;
				default: break;
			}
		}

		var tDly = tAckM.replace(msg.token, deliveryTokens[0]);
		var cD = " \
				ksx.plugins.MarchExtender.march.show(1, " + x + ", " + y + ", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [" + goldAmount + ", " + foodAmount + ", " + woodAmount + ", " + stoneAmount + ", " + oreAmount + ", " + aetherAmount + "]); \
				ksx.plugins.MarchExtender.march.transportTools.calculateFastestTroopsForTransport(); \
				var chat = document.getElementById('mod_comm_input'); \
				chat.value = '" + tDly + " / ??min';chat.focus(); \
				return false;";

		var ackStyle = "background: " + ksx.configuration.chat.backgrounds.RequestItemBackground;

		var actiondiv = document.createElement('div');
		actiondiv.setAttribute("style", "padding: 0 0 0 30px;");
		actiondiv.appendChild(ksx.Builder.GreenButton(culang.ksx_KoCButtler_ResourceRequest_DlyButtonTitle, cD));
		msg.msgdiv.appendChild(actiondiv);
		msg.msgdiv.setAttribute("style", ackStyle);

		return true;
	};
	this.atFootLowEntry = function (msg, filter) {
		/*DEBUGCODE:*/ GM_log("FoodLow token found");
		//DE: Mein Heiligtum TEST (777,888) hat zu wenig Nahrung sie reicht noch f?r 1,234,567 (1h 33m) - Verbrauch: -666,777
		//EN: My city Amsterdam (290,506) is low on food. Remaining: 7,629 (2h 16m) Upkeep: -3,348*/

		var allyFoodLowStyle = "background: " + ksx.configuration.chat.backgrounds.RequestItemBackground;
	
		var pattern = [];
		pattern['en'] = /.*\(([0-9]{1,3})\s*(,|-)\s*([0-9]{1,3})\).*\s([0-9,]+)\s\(([0-9\shms ]+)\).*Usage:\s([0-9,-]+)/img;
		//Mein Heiligtum kBraku (599,601) hat zu wenig Nahrung sie reicht noch f?r 106,168,260 (15Std. 47m ) - Verbrauch: -6,724,332
		pattern['de'] = /.*\(([0-9]{1,3})\s*(,|-)\s*([0-9]{1,3})\).*([0-9\s]+)\s\(([0-9\sdhms]+)\).*Produktion:\s([0-9\s-]+)/img;
		//Mon Sanctuaire kBraku (599,601) manque de nourriture 131,484,906 (19h 31m ) - Utilisation: -6,735,717
		pattern['fr'] = /.*\(([0-9]{1,3})\s*(,|-)\s*([0-9]{1,3})\).*\s([0-9,]+)\s\(([0-9\shms ]+)\).*Utilisation:\s([0-9,-]+)/img;
		//Mi Santuario kBraku (599,601) tiene poco alimento 151,976,874 (22h 35m ) - Uso: -6,728,614
		pattern['es'] = /.*\(([0-9]{1,3})\s*(,|-)\s*([0-9]{1,3})\).*\s([0-9,]+)\s\(([0-9\shms ]+)\).*Uso:\s([0-9,-]+)/img;
		//Il mio santuario kBraku (599,601) ha poco cibo, basta ancora per 31,087,035 (4h 37m ) - Consumo: -6,721,511
		pattern['it'] = /.*\(([0-9]{1,3})\s*(,|-)\s*([0-9]{1,3})\).*\s([0-9,]+)\s\(([0-9\shms ]+)\).*Consumo:\s([0-9,-]+)/img;
		//Benim Sehirim kBraku (599,601) in yiyecegi bitmesine kalan s?re 31,647,318 (4saat 42dakika ) - Gider: -6,721,511
		pattern['tr'] = /.*\(([0-9]{1,3})\s*(,|-)\s*([0-9]{1,3})\).*\s([0-9,]+)\s\((.+)\).*Gider:\s([0-9,-]+)/img;
		
		var match = pattern['en'].exec(msg.msgtxt);
		if (match === null) match = pattern['de'].exec(msg.msgtxt);
		if (match === null) match = pattern['fr'].exec(msg.msgtxt);
		if (match === null) match = pattern['es'].exec(msg.msgtxt);
		if (match === null) match = pattern['it'].exec(msg.msgtxt);
		if (match === null) match = pattern['tr'].exec(msg.msgtxt);
		if (match === null) {
			//Uuups
			GM_log("atFootLowEntry not match!? filter: "+filter.name);
			return true;
		}

		var x = match[1];
		var y = match[3];
		var foodleft = match[4].replace(/,/g,"").replace(/\s/g,"");
		var timeleft = match[5];
		var foodconsumption = match[6].replace(/,/g,"").replace(/\s/g,"");

		var foodAmount = -1 * foodconsumption * 8;

		if (ksxDebug) GM_log("FoodLow (Alli): " + x + "," + y + " " + foodleft + " " + timeleft + " " + foodconsumption + "/h -> " + foodAmount);
		

		
		// Bestaetigung
		var tAck = acknowledgeTokens[0] + " " + x + "," + y + " " + uW.g_js_strings.commonstr.food + " " + foodAmount;
		var cA = "var chat = document.getElementById('mod_comm_input'); chat.value = '" + tAck + "';chat.focus(); return false;";

		// Lieferung
		var tDly = deliveryTokens[0] + " " + x + "," + y + " " + uW.g_js_strings.commonstr.food + " " + foodAmount + " /??min";
		var cDt = "\
				ksx.plugins.MarchExtender.march.show(1, " + x + ", " + y + ", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, " + foodAmount + ", 0, 0, 0]); \
				ksx.plugins.MarchExtender.march.transportTools.calculateFastestTroopsForTransport(); \
				var chat = document.getElementById('mod_comm_input'); chat.value = '" + tDly + "'; \
				return false;";

		var actiondiv = document.createElement('div');
		actiondiv.setAttribute("style", "padding: 0 0 0 30px;");
		actiondiv.appendChild(ksx.Builder.GreenButton(culang.ksx_KoCButtler_ResourceRequest_AckButtonTitle, cA));
		actiondiv.appendChild(ksx.Builder.GreenButton(culang.ksx_KoCButtler_ResourceRequest_ExpressDlyButtonTitle, cDt));
		msg.msgdiv.appendChild(actiondiv);
		msg.msgdiv.setAttribute("style", allyFoodLowStyle);
		return true;
	};
	this.scanChatItem = function (msg, filter) {
		/*DEBUGCODE:*/if (ksxDebug) GM_log("ResourceRequestPlugin.scanChatItem");

		var dlyStyle = "background: " + ksx.configuration.chat.backgrounds.RequestItemBackground;
		
		if (msg.token0 == acknowledgeTokens[0] && !msg.isOwnEntry) {
			/*DEBUGCODE:*/if (ksxDebug) GM_log("ACKNOWLEDGE (alliance) token found");
			msg.msgdiv.setAttribute("style", dlyStyle);
			return true;
		} else if (msg.token0 == deliveryTokens[0] && !msg.isOwnEntry) {
			/*DEBUGCODE:*/if (ksxDebug) GM_log("DELIVERY (alliance) token found");
			msg.msgdiv.setAttribute("style", dlyStyle);
			return true;
			
		} else if (msg.token0 == foodLowTokens[0] && msg.isOwnEntry) {
			/*DEBUGCODE:*/if (ksxDebug) GM_log("FoodLow (own) token found");
			//msg.msgdiv.setAttribute("style", ownFoodLowStyle);
			return true;
		} else if (msg.token0 == foodLowTokens[0] && !msg.isOwnEntry) {
			/*DEBUGCODE:*/if (ksxDebug) GM_log("FoodLow (Alliance) token found");
//			return this.atFootLowEntry(msg, filter);
		}
		return false;
	};



	this.initUI();
	var filters = ksx.plugins.ChatMonitor.filters;
	var Filter = ksx.plugins.ChatMonitor.Filter;
	filters.push(new Filter('REQUEST-Own', requestTokens, { isOwnEntry: true }, this.scanChatItem));
	filters.push(new Filter('REQUEST-Alli', requestTokens, { isOwnEntry: false }, this.atRequestEntry));
	filters.push(new Filter('ACKNOWLEDGE-Own', acknowledgeTokens, { isOwnEntry: true }, this.atOwnAcknowledgeEntry));
	filters.push(new Filter('ACKNOWLEDGE-Alli', acknowledgeTokens, { isOwnEntry: false }, this.scanChatItem));
	filters.push(new Filter('DELIVERY', deliveryTokens, {}, this.scanChatItem));
	//filters.push(new Filter('FoodLow-Own', foodLowTokens, { isOwnEntry: true }, this.scanChatItem)); 
	filters.push(new Filter('FoodLow-Own', foodLowTokens, { isOwnEntry: true }, this.atFootLowEntry));
	filters.push(new Filter('FoodLow-Alli', foodLowTokens, { isOwnEntry: false }, this.atFootLowEntry));
};

function MarchExtenderPlugin(ksx) {
// 2012-05-05 FIX catapult not filled
// 2012-05-02 FIX textbox not filled out. -> usage of typeKeys2 changed.
// 2012-04-16 FIX Repeat Scout allways 0
// 2011-09-19 FIX NaN
// 2011-10-28 FIX troops not filled if any toop type was not available
// 2011-10-28 FIX troops not filled if march type was not 'repeat'

	var thisPlugin = this;
 
	this.march = {
		type: 0,
		ui: null,

		transportTools: {
			uiElement: null,
			uiElementId: "ksxTransportTools",

			hide: function () {
				if(ksxDebug) GM_log("MarchExtenderPlugin.march.transportTools.hide()");
				uiElement = ksx.tools.getElement("ksxTransportTools");
				if (!uiElement) return;
				uiElement.style.display = "none";
			},

			show: function (visible) {
				if (ksxDebug) GM_log("MarchExtenderPlugin.march.transportTools.show(" + Boolean(visible) + ")");
				var t = ksx.plugins.MarchExtender.march.transportTools;
				uiElement = ById(t.uiElementId);
				if (!uiElement) uiElement = t.create();
				t.uiElement.style.display = ((visible) ? "" : "none");
			},

			create: function (visible) {
				if (ksxDebug) GM_log("MarchExtenderPlugin.march.transportTools.create(" + Boolean(visible) + ")");
				var t = ksx.plugins.MarchExtender.march.transportTools;
				t.uiElement = ById(t.uiElementId);
				if (t.uiElement) return t.uiElement;
				
				//TODO KSX multilang
				if(typeof(culang.PredefinedTransports)=="undefined") culang.PredefinedTransports=(LangOptions.culang=="de") ? "Vordefinierte Transporte" : "Predefined Transports";
				if(typeof(culang.Training)=="undefined") culang.Training=(LangOptions.culang=="de") ? "Training" : "Training";
				if(typeof(culang.LastUsed)=="undefined") culang.LastUsed=(LangOptions.culang=="de") ? "Zuletzt verwendet" : "Last Used";
				if(typeof(culang.CalculateTroops)=="undefined") culang.CalculateTroops=(LangOptions.culang=="de") ? "Truppen Berechnen" : "Calculate Troops";
				var myString = " \
					<div class='section' > \
						<div class='section_title'>Transport Tools</div> \
						<div class='section_content' > \
							<a class='button20' href='#' onclick='ksx.plugins.MarchExtender.march.transportTools.calculateFastestTroopsForTransport();return false;'><span>{%CalculateTroops%}</span></a> \
							<a class='buttonGreen20' style='display:inline; position:absolute;margin-left:4px' href='#' onclick='ksx.plugins.MarchExtender.march.transportTools.calculateFastestTroopsForTransportHelp();return false;'><span>?</span></a> \
							<br/><br/> \
							<span> \
								{%PredefinedTransports%}:<br/>  \
								<select onchange='ksx.plugins.MarchExtender.march.transportTools.atTransportTemplateChanged(this);return false;' style='width: 307px'> \
										<option value=''><option> \
									<optgroup label='{%Training%} (4 {%cottages%}/{%stpop%} 18000, {%shrheavycavalry%},VP11,FP10)'> \
										<option value='0,1400000,2700000,0,180000'>{%supplytroop%} (18k)</option>	 \
										<option value='0,1940000,1800000,0,900000'>{%militiaman%} (18k)</option> \
										<option value='0,2660000,1800000,0,2700000'>{%scout%} (18k)</option> \
										<option value='0,3200000,9000000,0,1800000'>{%pikeman%} (18k)</option>	 \
										<option value='0,4100000,2700000,0,7200000'>{%swordsman%} (18k)</option> \
										<option value='0,2700000,3150000,0,2700000'>{%archer%} (9k)</option> \
										<option value='0,6500000,3600000,0,3000000'>{%cavalry%} (6k)</option>	 \
										<option value='0,6500000,1500000,0,7500000'>{%heavycavalry%} (3000)</option> \
										<option value='0,2700000,6750000,0,1575000'>{%supplywagon%} (4500)</option> \
										<option value='0,7250000,8100000,0,4860000'>{%ballista%} (2700)</option> \
										<option value='0,6500000,9000000,0,2250000'>{%batteringram%} (1500)</option> \
										<option value='0,5000000,5000000,8000000,1200000'>{%catapult%} (1000)</option> \
									</optgroup> \
									<optgroup label='{%Training%} ({%shrheavycavalry%} {%transport%})'> \
										<option value='0,4900000,5500000,0,2750000'>{%militiaman%} (55k, {%shrheavycavalry%},VP:9,FP:9)</option> \
										<option value='0,8500000,10000000,0,5000000'>{%militiaman%} (100k, {%shrheavycavalry%},VP:11,FP:10)</option> \
									</optgroup> \
									<optgroup label='{%LastUsed%}'> \
										<option value='0,1500000000,0,0,0'>{%food%} 1500mio</option>	 \
									</optgroup> \
								</select> \
									<a class='buttonGreen20' style='display:inline; position:absolute;margin-left:4px' href='#' onclick='ksx.plugins.MarchExtender.march.transportTools.transportTemplateHelp();return false;'><span>?</span></a> \
							</span> \
						</div> \
					</div> \
					";
				myString=culang.doTranslate(myString);
				var modalAttackTransport = ksx.tools.getElement("modal_attack_transport");
				t.uiElement = ksx.Builder.Element("div", myString);
				t.uiElement.setAttribute("id", t.uiElementId);
				t.uiElement.style.display = ((visible) ? "" : "none");
				modalAttackTransport.parentNode.appendChild(t.uiElement);
				return t.uiElement;
			},

			calculateFastestTroopsForTransport: function () {
				try {
					if (ksxDebug) GM_log("MarchExtenderPlugin.march.transportTools.calculateFastestTroopsForTransport");
					ui = new ksx.koc.MarchUI();

					var fp = uW.seed.tech["tch10"]; // Level Federgewicht-Pulver
					var maxUnits = Number(ui.maxUnit.textContent);
					var wagonLoad = 5000;
					var hKavLoad = 80;
					var kavLoad = 100;
					var scoutLoad = 5;
					var m = 1 * ui.gold.value + 1 * ui.food.value + 1 * ui.wood.value + 1 * ui.stone.value + 1 * ui.ore.value + 5 * ui.aestone.value;

					var cHKav  = Math.ceil(m / (hKavLoad  * (1 + fp / 10)));
					var cWagon = Math.ceil(m / (wagonLoad * (1 + fp / 10)));
					var cKav   = Math.ceil(m / (kavLoad   * (1 + fp / 10)));
					var cScout = Math.ceil(m / (scoutLoad * (1 + fp / 10)));
					if (ksxDebug) GM_log("Reset all units");
					for (var i = 1; i <= 12; i++) {
						if (!ui["unitIpt" + i]) GM_log("WARNING: calculateFastestTroopsForTransport - Element not specified - unitIpt" + i);
						//ui["unitIpt" + i].value = 0; ksx.tools.typeKeys2(ui["unitIpt" + i], "0");
						ui["unitIpt" + i].value = "0"; ksx.tools.typeKeys2(ui["unitIpt" + i], " ");
					}
					if (ksxDebug) GM_log("set best unit");
					if      (cScout < Number(ui.unitnum3.textContent) && cScout < maxUnits) {ui.unitIpt3.value=cScout; ksx.tools.typeKeys2(ui.unitIpt3, " ");}
					else if (cKav   < Number(ui.unitnum7.textContent) && cKav   < maxUnits) {ui.unitIpt7.value=cKav  ; ksx.tools.typeKeys2(ui.unitIpt7, " ");}
					else if (cHKav  < Number(ui.unitnum8.textContent) && cHKav  < maxUnits) {ui.unitIpt8.value=cHKav ; ksx.tools.typeKeys2(ui.unitIpt8, " ");}
					else if (cWagon < Number(ui.unitnum9.textContent) && cWagon < maxUnits) {ui.unitIpt9.value=cWagon; ksx.tools.typeKeys2(ui.unitIpt9, " ");}
				} catch (e) {
					GM_log("ERROR: MarchExtenderPlugin.calculateFastestTroopsForTransport - " + e);
					throw e;
				}
			},
			calculateFastestTroopsForTransportHelp: function () {
				ksx.Builder.showDialog("Truppen Berechnen", "Berechnet für die angegebenen Mengen, die schnellste Transportm?glichkeit.");
			},
			transportTemplateHelp: function () {
				ksx.Builder.showDialog("Vordefinierte Transporte", "Enthält ein Liste mit vordefinierte Transporten. Truppentrainingstransporte sind berechnet für 4 Hütten.");
			},

			atTransportTemplateChanged: function (sender) {
				if (ksxDebug) GM_log("MarchExtenderPlugin.march.transportTools.atTransportTemplateChanged(" + sender + ")");
				ui = new ksx.koc.MarchUI();
				var selectedValue = sender.options[sender.selectedIndex].value;
				GM_log("Seleted: \"" + selectedValue + "\"");
				if (selectedValue == "") return;
				var res = selectedValue.split(",");
				if (res.length != 5) {
					GM_log("ERROR: Buttler configuration! confEntry:\"" + selectedValue + "\"");
					return;
				}
				ui.gold   .value = res[0]; ksx.tools.typeKeys2(ui.gold   , " ");
				ui.food   .value = res[1]; ksx.tools.typeKeys2(ui.food   , " ");
				ui.wood   .value = res[2]; ksx.tools.typeKeys2(ui.wood   , " ");
				ui.stone  .value = res[3]; ksx.tools.typeKeys2(ui.stone  , " ");
				ui.ore    .value = res[4]; ksx.tools.typeKeys2(ui.ore    , " ");
				ui.aestone.value = res[5]; ksx.tools.typeKeys2(ui.aestone, " ");

				ksx.plugins.MarchExtender.march.transportTools.calculateFastestTroopsForTransport();
			},
			className: "MarchExtenderPlugin+TransportTools"
		},
		
		marchTools: {
			uiElement: null,
			uiElementId: "ksxMarchTools",

			hide: function () {
				if(ksxDebug) GM_log("MarchExtenderPlugin.march.marchTools.hide()");
				var t = ksx.plugins.MarchExtender.march.marchTools;
				uiElement = ById(t.uiElementId);
				if (!uiElement) return;
				uiElement.style.display = "none";
			},

			show: function (visible) {
				if (ksxDebug) GM_log("MarchExtenderPlugin.march.marchTools.show(" + Boolean(visible) + ")");
				var t = ksx.plugins.MarchExtender.march.marchTools;
				uiElement = ById(t.uiElementId);
				if (!uiElement) uiElement = t.create();
				t.uiElement.style.display = ((visible) ? "" : "none");
			},

			create: function (visible) {
				if (ksxDebug) GM_log("MarchExtenderPlugin.march.marchTools.create(" + Boolean(visible) + ")");
				var t = ksx.plugins.MarchExtender.march.marchTools;
				t.uiElement = ById(t.uiElementId);
				if (t.uiElement) return t.uiElement;
				if(typeof(culang.MarchTools)=="undefined") culang.MarchTools=(LangOptions.culang=="de") ? "MARSCH TOOLS" : "MARCH TOOLS";
				if(typeof(culang.SaveAllways)=="undefined") culang.SaveAllways=(LangOptions.culang=="de") ? "Immer Speichern" : "Save Allways";
				if(typeof(culang.SaveMarch)=="undefined") culang.SaveMarch=(LangOptions.culang=="de") ? "Marsch Speichern" : "Save March";
				var myString = " \
					<div class='section' > \
						<div class='section_title'>{%MarchTools%}</div> \
						<div class='section_content' > \
							<input id='ksxMarchExtenderMarchDescription' type='text' style='width: 300px' tooltip='name, description, comment, what ever you want'/> \
							<a class='buttonGreen20' style='display:inline; position:absolute;margin-left:4px' href='#' onclick='ksx.plugins.MarchExtender.march.marchTools.saveMarchDescriptionHelp();return false;'><span>?</span></a> \
							<br/><br/> \
							<a class='button20' href='#' onclick='ksx.plugins.MarchExtender.saveConfig();return false;'><span>{%SaveMarch%}</span></a> \
							<input id='ksxMarchExtenderMarchSaveAllways' type='checkbox' /> \
							<label for='ksxMarchExtenderMarchSaveAllways'>{%SaveAllways%}</label>\
							<a class='buttonGreen20' style='display:inline; position:absolute;margin-left:4px' href='#' onclick='ksx.plugins.MarchExtender.march.marchTools.saveMarchHelp();return false;'><span>?</span></a>\
						</div> \
					</div> \
					";
				myString=culang.doTranslate(myString);
				var modalAttackTransport = ksx.tools.getElement("modal_attack_transport");
				t.uiElement = ksx.Builder.Element("div", myString);
				t.uiElement.setAttribute("id", t.uiElementId);
				t.uiElement.style.display = ((visible) ? "" : "none");
				modalAttackTransport.parentNode.appendChild(t.uiElement);
				
				var saveAllways=ksx.tools.getElement("ksxMarchExtenderMarchSaveAllways");
				saveAllways.checked='checked';
				var marchDescription=ksx.tools.getElement("ksxMarchExtenderMarchDescription");
				marchDescription.text='';
				
				return t.uiElement;
			},

			saveMarchDescriptionHelp: function () {
				//TODO KSX
				//ksx.Builder.showDialog("Vordefinierte Transporte", "Enthält ein Liste mit vordefinierte Transporten. Truppentrainingstransporte sind berechnet für 4 Hütten.");
			},			
			saveMarchHelp: function () {
				//TODO KSX
				//ksx.Builder.showDialog("Vordefinierte Transporte", "Enthält ein Liste mit vordefinierte Transporten. Truppentrainingstransporte sind berechnet für 4 Hütten.");
			},


			className: "MarchExtenderPlugin+MarchTools"
		},

		show: function (type, x, y, troops, res) {
			// marchType: 1-Transport, 2-Reinforce, 3-Scout, 4-Attack, 5-Reassign
			// x,y
			// troops: array[12]
			// res: array[gold,food,wood,stone,ore]
			if (ksxDebug) GM_log("MarchExtenderPlugin.newMarch(...)");
			if (type === 'repeatlast' || type === 'repeatlast!') {
				var s = GM_getValue("LastMarch_" + ksx.koc.getServerId());
				if (!s) { /*No configuration*/return; };
				var cfg = ksx.JSON.parse(s);
				type = cfg[0];
				if (!x) x = cfg[1]; // param x will overwride cfg value
				if (!y) y = cfg[2]; // param y will overwride cfg value
				troops = cfg[3];
				res = cfg[4];
				if (!type) type = 1/*Transport*/;
			}
			ksx.plugins.MarchExtender.march.modalattack(type, x, y);
			ksx.plugins.MarchExtender.march.fill(type, x, y, troops, res);
		},
		
		modalattack: function (type, x, y) {
			//Workaround for NaN error. open the march with 'attack' und then switch to other tab
			// GM_log("modalattack type:" + type);
			ksx.tools.douW("modal_attack(" + 4 + ", '" + x + "', '" + y + "')", true);
			//add tab handler
			for (var i = 1; i < 6; i++) ById('modal_attack_tab_' + i).addEventListener('click', ksx.plugins.MarchExtender.march.atMarchTypeChanged, false);
			ksx.tools.click("modal_attack_tab_" + type);
			ksx.plugins.MarchExtender.march.type = type;
			if (typeof ksx.plugins.MarchExtender.original_modal_attack === "undefined") ksx.plugins.MarchExtender.march.init(type); //WORKAROUND if hooks not enabled
		},
		
		init: function (type) {
			if (typeof type == "undefined") type = ksx.koc.getCurrentMarchType();

			//add "March" click handler
			ById('btnMarch').addEventListener('click', ksx.plugins.MarchExtender.march.atMarchClicked, false);

			//TODO: create option
			ksx.tools.uncheck("modal_attack_supplyfilter_checkbox");

			//TODO: create option
			ksx.plugins.MarchExtender.march.transportTools.show((type == 1/*Transport*/ || type == 2/*Reinforce*/ || type == 5/*Reassign*/));
			ksx.plugins.MarchExtender.march.marchTools.show(true);
			
			if (!ksx.compatibility.disableMarchXYPaste)
				ksx.koc.attachXYPaste('modal_attack_target_coords_x', 'modal_attack_target_coords_y');
		},
		saveConfig: function () {
			if (ksxDebug) GM_log("MarchExtenderPlugin.saveMarchConfig()");
			var t = ksx.plugins.MarchExtender.march.transportTools;
			ui = new ksx.koc.MarchUI();

			var cfg = [
				ui.getMarchType(),
				ui.targetCoordsX.value, ui.targetCoordsY.value,
				[ui.unitIpt1.value, ui.unitIpt2.value, ui.unitIpt3.value, ui.unitIpt4.value, ui.unitIpt5.value, ui.unitIpt6.value, ui.unitIpt7.value, ui.unitIpt8.value, ui.unitIpt9.value, ui.unitIpt10.value, ui.unitIpt11.value, ui.unitIpt12.value],
				[ui.gold.value, ui.food.value, ui.wood.value, ui.stone.value, ui.ore.value, ui.aestone.value],
				[]
			];

			var s = ksx.JSON.stringify(cfg);
			if (ksxDebug) GM_log("Save 'LastMarch': " + s);
			GM_setValue("LastMarch_" + ksx.koc.getServerId(), s);
		},

		fill: function (type, x, y, troops, res) {
			if (ksxDebug) GM_log("MarchExtenderPlugin.march.fill("+type+","+x+","+y+",["+troops+"],["+res+"])");
			var ui = new ksx.koc.MarchUI();
			if (!type) type = 1;

			if (type == 1/*Transport*/) {
				ksx.tools.uncheck(ui.supplyfilterCheckbox);
			}
			
			for(i=1;i<=12;i++){
				if( (1*ui["unitAvail"+i]) >= troops[i-1] ){
					ui["unitIpt"+i].value = troops[i-1]; 
					ksx.tools.typeKeys2(ui["unitIpt"+i], " ");
				} else {
					GM_log("MarchExtenderPlugin: Not enought units available! type: "+i+", "+ui["unitAvail"+i]+"/"+troops[i-1]);
				}
			}

			ui.targetCoordsX.value = x;
			ui.targetCoordsY.value = y;

			if (type == 1/*Transport*/ || type == 2/*Reinforce*/ || type == 5/*Reassign*/) {
				ui.gold   .value = res[0]; ksx.tools.typeKeys2(ui.gold   , " ");
				ui.food   .value = res[1]; ksx.tools.typeKeys2(ui.food   , " ");
				ui.wood   .value = res[2]; ksx.tools.typeKeys2(ui.wood   , " ");
				ui.stone  .value = res[3]; ksx.tools.typeKeys2(ui.stone  , " ");
				ui.ore    .value = res[4]; ksx.tools.typeKeys2(ui.ore    , " ");
				ui.aestone.value = res[5]; ksx.tools.typeKeys2(ui.aestone, " ");
			}

			if (type == 4/*Attack*/) {
				// ui.attackKnight.selectedIndex = ui.attackKnight.options.length - 1; // select last
			}
		},

		atMarchTypeChanged: function (evt) {
			if (ksxDebug) GM_log("MarchExtenderPlugin.atMarchTypeChanged");
			type = parseInt(evt.target.id.substr(17)); //modal_attack_tab_{marchType}
			var ui = new ksx.koc.MarchUI();

			//TODO create config option
			ksx.plugins.MarchExtender.march.transportTools.show((type == 1/*Transport*/ || type == 2/*Reinforce*/ || type == 5/*Reassign*/));

			if (type == 3/*Scout*/) {
				GM_log("atMarchTypeChanged 3 "+(ui.unitAvail3 >0));
				//TODO create config option	
				setTimeout(function(){
					var ui = new ksx.koc.MarchUI();
					var ksx=uWs.ksx;
					if(ui.unitAvail3 >0){ui.unitIpt3.value = 1; ksx.tools.typeKeys(ui.unitIpt3, " ");}
				},500);
			}
			if (type == 1/*Transport*/) {
				//TODO create config option
				ksx.tools.uncheck(ui.supplyfilterCheckbox);
			}

			switch (type) {
				case 1/*Transport*/: break;
				case 2/*Reinforce*/: break;
				case 3/*Scout    */: break;
				case 4/*Attack   */: break;
				case 5/*Reassign */: break;
				default: break;
			}
		},
		atMarchClicked: function () {
			if (ksxDebug) GM_log("MarchExtenderPlugin.atMarchClicked()");
			var saveAllways=ksx.tools.getElement("ksxMarchExtenderMarchSaveAllways");
			if(saveAllways.checked='checked')
				ksx.plugins.MarchExtender.march.saveConfig();
		},

		className: "MarchExtenderPlugin+March"
	},

	this.unsafeModalAttackHook = function (marchType, x, y) {
		//if(ksxDebug) GM_log("MarchExtenderPlugin.unsafeModalAttackHook(..)");

		/*ORIGINAL CALL*/
		var ret = ksx.plugins.MarchExtender.original_modal_attack(marchType, x, y);
		/*WORKAROUND  [Power]*/
		if (typeof attackDialog_hook === "function") attackDialog_hook(marchType, x, y); // 

		ksx.plugins.MarchExtender.march.init(marchType);
		return ret;
	};
	
	this.unsafeModalAttackCheckHook=function() {
		/*WORKAROUND [Power]*/ 
		if(typeof modalAttack_hook === "function") modalAttack_hook();
		/*NEWCALL*/ 
		ksx.plugins.MarchExtender.saveMarchConfig();
		/*ORIGINALCALL*/
		var ret=ksx.plugins.MarchExtender.original_modal_attack_check();
		return ret;
	};

	this.setHooks = function () {
		if(ksxDebug) GM_log("MarchExtenderPlugin.setHooks");
		if (typeof uW.modal_attack != "function") {/*UUPS*/GM_log("Check KoC: 'modal_attack' not found!");return;}

		thisPlugin.original_modal_attack = uW.modal_attack;
		uW.modal_attack = this.unsafeModalAttackHook;

//      not used! event handler attached instead
//		thisPlugin.original_modal_attack_check = uW.modal_attack_check;
//		uW.modal_attack_check = this.unsafeModalAttackCheckHook;
	};
	
	// @PDX: Schau mal bitte, wenn ich meine hooks setze, funktionieren deine hooks nicht mehr.
	// die WORKAROUNDs rufen als Notl?sung zwar deine Funktionen auf, aber eine sauber L?sung  ist das leider nicht.
	thisPlugin.setHooks();

	if (ksx.plugins.Toolbar != null) {
		var ksxMarchExtenderRepeatOpen = ById("ksxMarchExtenderRepeatOpen");
		if (ksxMarchExtenderRepeatOpen) ksxMarchExtenderRepeatOpen.addEventListener("click", function () { thisPlugin.march.show('repeatlast', '', '', [], []); }, false);
		var ksxMarchExtenderRepeatMarch = ById("ksxMarchExtenderRepeatMarch");
		if (ksxMarchExtenderRepeatMarch) ksxMarchExtenderRepeatOpen.addEventListener("click", function () { thisPlugin.march.show('repeatlast!', '', '', [], []); }, false);
	}
}

function ReportsPlugin(ksx) {
	var thisPlugin = this;
	var t = {
		maxPages: 1, //t.maxPages = ById("pagesSelect").value;
		totalPages: 0
	};

	this.show = function () {
		t.totalPages = 0;
		t.maxPages = 10;
		thisPlugin.searchReports("", 1);
	};

	this.searchReports = function (rslt, pageNum) {
		if (t.totalPages == 0) {
			var params = uW.Object.clone(uW.g_ajaxparams);
			params.pf = 0;
			params.group = "a";
			params.pageNo = 1;

			new ksx.koc.MyAjaxRequest(uW.g_ajaxpath + "ajax/listReports.php" + uW.g_ajaxsuffix, {
				method: "post",
				parameters: params,
				onSuccess: function (rslt) {
					if (rslt.ok) {
						GM_log("ReportsPlugin.searchReports.onSuccess OK");
						t.totalPages = parseInt(rslt['totalPages']);
					} else {
						GM_log("ReportsPlugin.searchReports.onSuccess ERR");
					}
				},
				onFailure: function () {
					GM_log("ReportsPlugin.searchReports.onFailure");
				}
			}, false);
		}

		if (t.maxPages == 101) t.maxPages = t.totalPages;

		if (parseInt(pageNum) <= t.maxPages) {
			//ById('searchStatus').innerHTML = pageNum;
			GM_log(">>ReportsPlugin.getReports " + pageNum);
			thisPlugin.getReports(pageNum);
		} else {
			//ById('searchStatus').innerHTML = "Fertig!";
			GM_log("ReportsPlugin Fertig");
		}
	};

	this.getReports = function(pageNum) {
//		var t = Tabs.msg;
		var params = uW.Object.clone(uW.g_ajaxparams);
		params.pf = 0;
		params.group = "a";
		params.pageNo = pageNum;

		var req=new ksx.koc.MyAjaxRequest(uW.g_ajaxpath + "ajax/listReports.php" + uW.g_ajaxsuffix, {
			method: "post",
			parameters: params,
			onSuccess: function(rslt) {
				if (rslt.ok) {
					GM_log("ReportsPlugin.getReports.onSuccess OK");
					GM_log(">>ReportsPlugin searchInReports " + pageNum);
					thisPlugin.searchInReports(rslt, pageNum);
				}else {
					GM_log("ReportsPlugin.getReports.onSuccess ERR");
				}
			},
			onFailure: function () {
				GM_log("ReportsPlugin.getReports.onFailure");
			}
		}, false);
	};

	this.searchInReports = function(rslt, pageNum) {
//		var t = Tabs.msg;

		var myarray = rslt['arReports'];
		var results = ById("ReportResults");

		for (k in myarray) {
			if (getMyAlliance()[0] != myarray[k]['side1AllianceId'] || myarray[k]['marchType'] == 2) {
				t.content += '<TR><TD><A><SPAN onclick="getReport(' + myarray[k]['reportId'] + ',' + myarray[k]['side0TileType'] + ')">'+culang.mainShow+'</span></a></td>';
				t.content += '<TD>' + pageNum + '</td>';
				t.content += '<TD>' + uW.formatDateByUnixTime(myarray[k]['reportUnixTime']) + '</td>';
				t.content += '<TD>';
				if (rslt['arPlayerNames']['g' + myarray[k]['side1PlayerId']] == "M") t.content += 'Lord ';
				if (rslt['arPlayerNames']['g' + myarray[k]['side1PlayerId']] == "F") t.content += 'Lady ';
				t.content += rslt['arPlayerNames']['p' + myarray[k]['side1PlayerId']] + '</td>';
				t.content += '<td>' + pdxkoordlink(myarray[k]['side1XCoord'], myarray[k]['side1YCoord']) + '</td>';
				t.content += '<TD>' + rslt['arAllianceNames']['a' + myarray[k]['side1AllianceId']] + '</td>';
				if (myarray[k]['marchType'] == 2) t.content += '<TD><FONT color="00CC33">'+culang.mainReinforce+'</font></td>';
				if (myarray[k]['marchType'] == 3) t.content += '<TD><FONT color="FF9933">'+culang.mainScout+'</font></td>';
				if (myarray[k]['marchType'] == 4) t.content += '<TD><FONT color="FF0033">'+culang.mainAttack+'</font></td>';
				t.content += '<TD>';
				if (rslt['arPlayerNames']['g' + myarray[k]['side0PlayerId']] == "M") t.content += 'Lord ';
				if (rslt['arPlayerNames']['g' + myarray[k]['side0PlayerId']] == "F") t.content += 'Lady ';
				t.content += rslt['arPlayerNames']['p' + myarray[k]['side0PlayerId']] + '</td>';
				if (myarray[k]['side0TileType'] == 51) t.content += '<TD>Stadt (' + myarray[k]['side0TileLevel'] + ')</td>';
				else t.content += '<TD><FONT color="#909090"> Wild (' + myarray[k]['side0TileLevel'] + ')</font></td>';
				t.content += '<td>' + pdxkoordlink(myarray[k]['side0XCoord'], myarray[k]['side0YCoord']) + '</td>';
			}
		}
		results.innerHTML = t.content;
		pageNum++;
		t.searchReports(rslt, pageNum);
	};
} 

//	┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
//	│  	### EOF ###					 						 │
//	│   KOC POWER ALL - Elite | BUTTLER									 │
//	└────────────────────────────────────────────────────────────────────────────────────────────────────────┘